diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 44258d64c59ea..7892c5dde5f8b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -51,3 +51,4 @@ src/Features/**/PublicAPI.Unshipped.txt @dotnet/roslyn-api-owners src/EditorFeatures/**/PublicAPI.Unshipped.txt @dotnet/roslyn-api-owners src/Tools/ExternalAccess/OmniSharp*/ @333fred @joerobich +src/Tools/ExternalAccess/RazorCompiler @dotnet/roslyn-compiler diff --git a/Compilers.sln b/Compilers.sln index 62127a253d88a..0d463ad693c86 100644 --- a/Compilers.sln +++ b/Compilers.sln @@ -165,6 +165,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.CSha EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestDiscoveryWorker", "src\Tools\TestDiscoveryWorker\TestDiscoveryWorker.csproj", "{FB617466-C4A1-4289-A512-A06182FC779F}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ExternalAccess", "ExternalAccess", "{67B6F694-CA27-4CDE-B1E5-E2B4105A2420}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler", "src\Tools\ExternalAccess\RazorCompiler\Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler.csproj", "{8450EF6B-28BB-4F4D-B005-CD734B476800}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -423,6 +427,10 @@ Global {FB617466-C4A1-4289-A512-A06182FC779F}.Debug|Any CPU.Build.0 = Debug|Any CPU {FB617466-C4A1-4289-A512-A06182FC779F}.Release|Any CPU.ActiveCfg = Release|Any CPU {FB617466-C4A1-4289-A512-A06182FC779F}.Release|Any CPU.Build.0 = Release|Any CPU + {8450EF6B-28BB-4F4D-B005-CD734B476800}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8450EF6B-28BB-4F4D-B005-CD734B476800}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8450EF6B-28BB-4F4D-B005-CD734B476800}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8450EF6B-28BB-4F4D-B005-CD734B476800}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -499,6 +507,8 @@ Global {48C93F90-8776-4847-96D8-127B896D6C80} = {C65C6143-BED3-46E6-869E-9F0BE6E84C37} {F3D9264A-7CAE-4265-AF48-0C863301F51E} = {32A48625-F0AD-419D-828B-A50BDABA38EA} {FB617466-C4A1-4289-A512-A06182FC779F} = {FD0FAF5F-1DED-485C-99FA-84B97F3A8EEC} + {67B6F694-CA27-4CDE-B1E5-E2B4105A2420} = {FD0FAF5F-1DED-485C-99FA-84B97F3A8EEC} + {8450EF6B-28BB-4F4D-B005-CD734B476800} = {67B6F694-CA27-4CDE-B1E5-E2B4105A2420} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {6F599E08-A9EA-4FAA-897F-5D824B0210E6} diff --git a/Compilers.slnf b/Compilers.slnf index 26e6beb9d51ba..762c96be41e6c 100644 --- a/Compilers.slnf +++ b/Compilers.slnf @@ -44,6 +44,7 @@ "src\\Test\\PdbUtilities\\Roslyn.Test.PdbUtilities.csproj", "src\\Compilers\\Test\\Core\\Microsoft.CodeAnalysis.Test.Utilities.csproj", "src\\Tools\\AnalyzerRunner\\AnalyzerRunner.csproj", + "src\\Tools\\ExternalAccess\\RazorCompiler\\Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler.csproj", "src\\Tools\\Source\\CompilerGeneratorTools\\Source\\BoundTreeGenerator\\CompilersBoundTreeGenerator.csproj", "src\\Tools\\Source\\CompilerGeneratorTools\\Source\\CSharpErrorFactsGenerator\\CSharpErrorFactsGenerator.csproj", "src\\Tools\\Source\\CompilerGeneratorTools\\Source\\CSharpSyntaxGenerator\\CSharpSyntaxGenerator.csproj", diff --git a/Roslyn.sln b/Roslyn.sln index 552fc9c305112..4070ee47d994e 100644 --- a/Roslyn.sln +++ b/Roslyn.sln @@ -519,12 +519,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CommonLanguageSer EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.TestAnalyzerReference", "src\Workspaces\TestAnalyzerReference\Microsoft.CodeAnalysis.TestAnalyzerReference.csproj", "{8A29449D-411E-49E4-B99E-E8428076BB21}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.CSharp.LanguageServer.Protocol", "src\Features\LanguageServer\Microsoft.CodeAnalysis.CSharp.LanguageServer.Protocol\Microsoft.CodeAnalysis.CSharp.LanguageServer.Protocol.csproj", "{4C1B26EE-465B-4B30-9E50-0285EF7AB035}" -EndProject -Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "Microsoft.CodeAnalysis.VisualBasic.LanguageServer.Protocol", "src\Features\LanguageServer\Microsoft.CodeAnalysis.VisualBasic.LanguageServer.Protocol\Microsoft.CodeAnalysis.VisualBasic.LanguageServer.Protocol.vbproj", "{F836BDB1-4EC7-4F4C-B2E9-BCD721C9E650}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestDiscoveryWorker", "src\Tools\TestDiscoveryWorker\TestDiscoveryWorker.csproj", "{8BC50AFF-1EBF-4E9A-AEBB-04F387AA800F}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler", "src\Tools\ExternalAccess\RazorCompiler\Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler.csproj", "{E5E0BF73-95F7-4BC3-8443-2336C4FF4297}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1271,18 +1269,14 @@ Global {8A29449D-411E-49E4-B99E-E8428076BB21}.Debug|Any CPU.Build.0 = Debug|Any CPU {8A29449D-411E-49E4-B99E-E8428076BB21}.Release|Any CPU.ActiveCfg = Release|Any CPU {8A29449D-411E-49E4-B99E-E8428076BB21}.Release|Any CPU.Build.0 = Release|Any CPU - {4C1B26EE-465B-4B30-9E50-0285EF7AB035}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4C1B26EE-465B-4B30-9E50-0285EF7AB035}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4C1B26EE-465B-4B30-9E50-0285EF7AB035}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4C1B26EE-465B-4B30-9E50-0285EF7AB035}.Release|Any CPU.Build.0 = Release|Any CPU - {F836BDB1-4EC7-4F4C-B2E9-BCD721C9E650}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F836BDB1-4EC7-4F4C-B2E9-BCD721C9E650}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F836BDB1-4EC7-4F4C-B2E9-BCD721C9E650}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F836BDB1-4EC7-4F4C-B2E9-BCD721C9E650}.Release|Any CPU.Build.0 = Release|Any CPU {8BC50AFF-1EBF-4E9A-AEBB-04F387AA800F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8BC50AFF-1EBF-4E9A-AEBB-04F387AA800F}.Debug|Any CPU.Build.0 = Debug|Any CPU {8BC50AFF-1EBF-4E9A-AEBB-04F387AA800F}.Release|Any CPU.ActiveCfg = Release|Any CPU {8BC50AFF-1EBF-4E9A-AEBB-04F387AA800F}.Release|Any CPU.Build.0 = Release|Any CPU + {E5E0BF73-95F7-4BC3-8443-2336C4FF4297}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E5E0BF73-95F7-4BC3-8443-2336C4FF4297}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E5E0BF73-95F7-4BC3-8443-2336C4FF4297}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E5E0BF73-95F7-4BC3-8443-2336C4FF4297}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1519,9 +1513,8 @@ Global {BD9539EB-AA5E-4E67-AC7F-97D7CBC4D0C9} = {3E5FE3DB-45F7-4D83-9097-8F05D3B3AEC6} {58AD1B2C-6FFC-47CB-838A-54D0CA2BF0C8} = {3E5FE3DB-45F7-4D83-9097-8F05D3B3AEC6} {8A29449D-411E-49E4-B99E-E8428076BB21} = {55A62CFA-1155-46F1-ADF3-BEEE51B58AB5} - {4C1B26EE-465B-4B30-9E50-0285EF7AB035} = {3E5FE3DB-45F7-4D83-9097-8F05D3B3AEC6} - {F836BDB1-4EC7-4F4C-B2E9-BCD721C9E650} = {3E5FE3DB-45F7-4D83-9097-8F05D3B3AEC6} {8BC50AFF-1EBF-4E9A-AEBB-04F387AA800F} = {FD0FAF5F-1DED-485C-99FA-84B97F3A8EEC} + {E5E0BF73-95F7-4BC3-8443-2336C4FF4297} = {8977A560-45C2-4EC2-A849-97335B382C74} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {604E6B91-7BC0-4126-AE07-D4D2FEFC3D29} diff --git a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md index a749eb2266dc6..8cd2f482029e5 100644 --- a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md +++ b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md @@ -1,5 +1,67 @@ # This document lists known breaking changes in Roslyn after .NET 6 all the way to .NET 7. +## Ref safety errors do not affect conversion from lambda expression to delegate + +***Introduced in Visual Studio 2022 version 17.5*** + +Ref safety errors reported in a lambda body no longer affect whether the lambda expression is convertible to a delegate type. This change can affect overload resolution. + +In the example below, the call to `M(x => ...)` is ambiguous with Visual Studio 17.5 because both `M(D1)` and `M(D2)` are now considered applicable, even though the call to `F(ref x, ref y)` within the lambda body will result in a ref safety with `M(D1)` (see the examples in `d1` and `d2` for comparison). Previously, the call bound unambiguously to `M(D2)` because the `M(D1)` overload was considered not applicable. +```csharp +using System; + +ref struct R { } + +delegate R D1(R r); +delegate object D2(object o); + +class Program +{ + static void M(D1 d1) { } + static void M(D2 d2) { } + + static void F(ref R x, ref Span y) { } + static void F(ref object x, ref Span y) { } + + static void Main() + { + // error CS0121: ambiguous between: 'M(D1)' and 'M(D2)' + M(x => + { + Span y = stackalloc int[1]; + F(ref x, ref y); + return x; + }); + + D1 d1 = x1 => + { + Span y1 = stackalloc int[1]; + F(ref x1, ref y1); // error CS8352: 'y2' may expose referenced variables + return x1; + }; + + D2 d2 = x2 => + { + Span y2 = stackalloc int[1]; + F(ref x2, ref y2); // ok: F(ref object x, ref Span y) + return x2; + }; + } +} +``` + +To workaround the overload resolution changes, use explicit types for the lambda parameters or delegate. + +```csharp + // ok: M(D2) + M((object x) => + { + Span y = stackalloc int[1]; + F(ref x, ref y); // ok: F(ref object x, ref Span y) + return x; + }); +``` + ## Raw string interpolations at start of line. ***Introduced in Visual Studio 2022 version 17.5*** diff --git a/docs/features/incremental-generators.md b/docs/features/incremental-generators.md index df259799d1e75..27a438b2dbca9 100644 --- a/docs/features/incremental-generators.md +++ b/docs/features/incremental-generators.md @@ -206,18 +206,14 @@ transformations together: Consider the following simple example: ```csharp -initContext.RegisterExecutionPipeline(static context => -{ - // get the additional text provider - IncrementalValuesProvider additionalTexts = context.AdditionalTextsProvider; - - // apply a 1-to-1 transform on each text, which represents extracting the path - IncrementalValuesProvider transformed = additionalTexts.Select(static (text, _) => text.Path); +// get the additional text provider +IncrementalValuesProvider additionalTexts = initContext.AdditionalTextsProvider; - // transform each extracted path into something else - IncrementalValuesProvider prefixTransform = transformed.Select(static (path, _) => "prefix_" + path); +// apply a 1-to-1 transform on each text, which represents extracting the path +IncrementalValuesProvider transformed = additionalTexts.Select(static (text, _) => text.Path); -}); +// transform each extracted path into something else +IncrementalValuesProvider prefixTransform = transformed.Select(static (path, _) => "prefix_" + path); ``` Note how `transformed` and `prefixTransform` are themselves an @@ -369,17 +365,14 @@ distinct item for generation, effectively splitting a single additional file into multiple sub-items. ``` csharp -initContext.RegisterExecutionPipeline(static context => -{ - // get the additional text provider - IncrementalValuesProvider additionalTexts = context.AdditionalTextsProvider; +// get the additional text provider +IncrementalValuesProvider additionalTexts = initContext.AdditionalTextsProvider; - // extract each element from each additional file - IncrementalValuesProvider elements = additionalTexts.SelectMany(static (text, _) => /*transform text into an array of MyElementType*/); +// extract each element from each additional file +IncrementalValuesProvider elements = additionalTexts.SelectMany(static (text, _) => /*transform text into an array of MyElementType*/); - // now the generator can consider the union of elements in all additional texts, without needing to consider multiple files - IncrementalValuesProvider transformed = elements.Select(static (element, _) => /*transform the individual element*/); -} +// now the generator can consider the union of elements in all additional texts, without needing to consider multiple files +IncrementalValuesProvider transformed = elements.Select(static (element, _) => /*transform the individual element*/); ``` ### Where @@ -422,14 +415,11 @@ interested in. For example, the generator will likely want to filter additional texts on file extensions: ```csharp -initContext.RegisterExecutionPipeline(static context => -{ - // get the additional text provider - IncrementalValuesProvider additionalTexts = context.AdditionalTextsProvider; +// get the additional text provider +IncrementalValuesProvider additionalTexts = initContext.AdditionalTextsProvider; - // filter additional texts by extension - IncrementalValuesProvider xmlFiles = additionalTexts.Where(static (text, _) => text.Path.EndsWith(".xml", StringComparison.OrdinalIgnoreCase)); -} +// filter additional texts by extension +IncrementalValuesProvider xmlFiles = additionalTexts.Where(static (text, _) => text.Path.EndsWith(".xml", StringComparison.OrdinalIgnoreCase)); ``` ### Collect @@ -464,18 +454,14 @@ IncrementalValuesProvider IncrementalValueProvider -{ - // get the additional text provider - IncrementalValuesProvider additionalTexts = context.AdditionalTextsProvider; +// get the additional text provider +IncrementalValuesProvider additionalTexts = initContext.AdditionalTextsProvider; - // collect the additional texts into a single item - IncrementalValueProvider collected = context.AdditionalTexts.Collect(); - - // perform a transformation where you can access all texts at once - var transform = collected.Select(static (texts, _) => /* ... */); -} +// collect the additional texts into a single item +IncrementalValueProvider collected = additionalTexts.Collect(); +// perform a transformation where you can access all texts at once +var transform = collected.Select(static (texts, _) => /* ... */); ``` ### Multi-path pipelines @@ -520,18 +506,15 @@ Those transforms can then be used as the inputs to new single path transforms, i For example: ```csharp -initContext.RegisterExecutionPipeline(static context => -{ - // get the additional text provider - IncrementalValuesProvider additionalTexts = context.AdditionalTextsProvider; +// get the additional text provider +IncrementalValuesProvider additionalTexts = context.AdditionalTextsProvider; - // apply a 1-to-1 transform on each text, extracting the path - IncrementalValuesProvider transformed = additionalTexts.Select(static (text, _) => text.Path); +// apply a 1-to-1 transform on each text, extracting the path +IncrementalValuesProvider transformed = additionalTexts.Select(static (text, _) => text.Path); - // split the processing into two paths of derived data - IncrementalValuesProvider nameTransform = transformed.Select(static (path, _) => "prefix_" + path); - IncrementalValuesProvider extensionTransform = transformed.Select(static (path, _) => Path.ChangeExtension(path, ".new")); -} +// split the processing into two paths of derived data +IncrementalValuesProvider nameTransform = transformed.Select(static (path, _) => "prefix_" + path); +IncrementalValuesProvider extensionTransform = transformed.Select(static (path, _) => Path.ChangeExtension(path, ".new")); ``` `nameTransform` and `extensionTransform` produce different values for the same @@ -671,23 +654,19 @@ With the above transformations the generator author can now take one or more inputs and combine them into a single source of data. For example: ```csharp -initContext.RegisterExecutionPipeline(static context => -{ - // get the additional text provider - IncrementalValuesProvider additionalTexts = context.AdditionalTextsProvider; - - // combine each additional text with the parse options - IncrementalValuesProvider<(AdditionalText, ParseOptions)> combined = context.AdditionalTextsProvider.Combine(context.ParseOptionsProvider); +// get the additional text provider +IncrementalValuesProvider additionalTexts = initContext.AdditionalTextsProvider; - // perform a transform on each text, with access to the options - var transformed = combined.Select(static (pair, _) => - { - AdditionalText text = pair.Left; - ParseOptions parseOptions = pair.Right; +// combine each additional text with the parse options +IncrementalValuesProvider<(AdditionalText, ParseOptions)> combined = initContext.AdditionalTextsProvider.Combine(initContext.ParseOptionsProvider); - // do the actual transform ... - }); -} +// perform a transform on each text, with access to the options +var transformed = combined.Select(static (pair, _) => +{ + AdditionalText text = pair.Left; + ParseOptions parseOptions = pair.Right; + // do the actual transform ... +}); ``` If either of the inputs to a combine change, then subsequent transformation will @@ -751,12 +730,9 @@ public class Class3 {} As an author I can make an input node that extracts the return type information ```csharp -initContext.RegisterExecutionPipeline(static context => -{ - // create a syntax provider that extracts the return type kind of method symbols - var returnKinds = context.SyntaxProvider.CreateSyntaxProvider(static (n, _) => n is MethodDeclarationSyntax, +// create a syntax provider that extracts the return type kind of method symbols + var returnKinds = initContext.SyntaxProvider.CreateSyntaxProvider(static (n, _) => n is MethodDeclarationSyntax, static (n, _) => ((IMethodSymbol)n.SemanticModel.GetDeclaredSymbol(n.Node)).ReturnType.Kind); -} ``` Initially the `predicate` will run for all syntax nodes, and select the two @@ -856,21 +832,19 @@ For example, a generator can extract out the set of paths for the additional files and create a method that prints them out: ``` csharp -initContext.RegisterExecutionPipeline(static context => -{ - // get the additional text provider - IncrementalValuesProvider additionalTexts = context.AdditionalTextsProvider; +// get the additional text provider +IncrementalValuesProvider additionalTexts = initContext.AdditionalTextsProvider; - // apply a 1-to-1 transform on each text, extracting the path - IncrementalValuesProvider transformed = additionalTexts.Select(static (text, _) => text.Path); +// apply a 1-to-1 transform on each text, extracting the path +IncrementalValuesProvider transformed = additionalTexts.Select(static (text, _) => text.Path); - // collect the paths into a batch - IncrementalValueProvider> collected = transformed.Collect(); - - // take the file paths from the above batch and make some user visible syntax - initContext.RegisterSourceOutput(collected, static (sourceProductionContext, filePaths) => - { - sourceProductionContext.AddSource("additionalFiles.cs", @" +// collect the paths into a batch +IncrementalValueProvider> collected = transformed.Collect(); + +// take the file paths from the above batch and make some user visible syntax +initContext.RegisterSourceOutput(collected, static (sourceProductionContext, filePaths) => +{ + sourceProductionContext.AddSource("additionalFiles.cs", @" namespace Generated { public class AdditionalTextList @@ -881,8 +855,7 @@ namespace Generated } } }"); - }); -} +}); ``` **RegisterImplementationSourceOutput**: diff --git a/docs/features/source-generators.cookbook.md b/docs/features/source-generators.cookbook.md index dc390d986c3ea..bf69c475eab7d 100644 --- a/docs/features/source-generators.cookbook.md +++ b/docs/features/source-generators.cookbook.md @@ -11,6 +11,34 @@ of scope in the final design of the shipping feature. **This document expands on the details in the [full design document](source-generators.md), please ensure you have read that first.** +## Table of content + +- [Source Generators Cookbook](#source-generators-cookbook) + - [Table of content](#table-of-content) + - [Summary](#summary) + - [Proposal](#proposal) + - [Out of scope designs](#out-of-scope-designs) + - [Language features](#language-features) + - [Code rewriting](#code-rewriting) + - [Conventions](#conventions) + - [Designs](#designs) + - [Generated class](#generated-class) + - [Additional file transformation](#additional-file-transformation) + - [Augment user code](#augment-user-code) + - [Issue Diagnostics](#issue-diagnostics) + - [INotifyPropertyChanged](#inotifypropertychanged) + - [Package a generator as a NuGet package](#package-a-generator-as-a-nuget-package) + - [Use functionality from NuGet packages](#use-functionality-from-nuget-packages) + - [Access Analyzer Config properties](#access-analyzer-config-properties) + - [Consume MSBuild properties and metadata](#consume-msbuild-properties-and-metadata) + - [Unit Testing of Generators](#unit-testing-of-generators) + - [Participate in the IDE experience](#participate-in-the-ide-experience) + - [Serialization](#serialization) + - [Auto interface implementation](#auto-interface-implementation) + - [Breaking Changes:](#breaking-changes) + - [Open Issues](#open-issues) + + ## Proposal As a reminder, the high level design goals of source generators are: diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index f5d7cc7181436..41a3264c9b6c9 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -13,22 +13,22 @@ - + https://github.com/dotnet/arcade - 5da4fd65d650129f1771e2fb55e296161b654b85 + eae015fb1c92ceef69126164b3969447d0355c08 https://github.com/dotnet/roslyn 5d10d428050c0d6afef30a072c4ae68776621877 - + https://github.com/dotnet/arcade - 5da4fd65d650129f1771e2fb55e296161b654b85 + eae015fb1c92ceef69126164b3969447d0355c08 - + https://github.com/dotnet/roslyn-analyzers - ea8aa10a9b2cf153701dc79994d6c3c5e9c17d0a + 0b2bc22f087f4a42915a3f5d7049a0e71a179423 diff --git a/eng/Versions.props b/eng/Versions.props index 29b1a7ae04713..03254707ab1cf 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -6,9 +6,9 @@ --> 4 - 5 + 6 0 - 3 + 1 $(MajorVersion).$(MinorVersion).$(PatchVersion) 3.3.4-beta1.22579.2 - 8.0.0-preview1.22614.3 + 8.0.0-preview1.23058.2 1.1.2-beta1.22512.1 0.1.149-beta @@ -291,7 +291,7 @@ create a test insertion in Visual Studio to validate. --> 13.0.1 - 2.14.17-alpha + 2.14.20 - - - - - - - - - - - - - - - diff --git a/global.json b/global.json index affb3fb79f549..b8f5dd4d0e0ed 100644 --- a/global.json +++ b/global.json @@ -12,7 +12,7 @@ "xcopy-msbuild": "17.4.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.22615.3", - "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.22615.3" + "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.23054.2", + "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.23054.2" } } diff --git a/src/Analyzers/CSharp/Analyzers/CodeStyle/CSharpAnalyzerOptionsProvider.cs b/src/Analyzers/CSharp/Analyzers/CodeStyle/CSharpAnalyzerOptionsProvider.cs index 669ba112e3e21..2747ec66fb12d 100644 --- a/src/Analyzers/CSharp/Analyzers/CodeStyle/CSharpAnalyzerOptionsProvider.cs +++ b/src/Analyzers/CSharp/Analyzers/CodeStyle/CSharpAnalyzerOptionsProvider.cs @@ -23,20 +23,20 @@ internal readonly struct CSharpAnalyzerOptionsProvider /// /// Document editorconfig options. /// - private readonly AnalyzerConfigOptions _options; + private readonly IOptionsReader _options; /// /// Fallback options - the default options in Code Style layer. /// private readonly IdeAnalyzerOptions _fallbackOptions; - public CSharpAnalyzerOptionsProvider(AnalyzerConfigOptions options, IdeAnalyzerOptions fallbackOptions) + public CSharpAnalyzerOptionsProvider(IOptionsReader options, IdeAnalyzerOptions fallbackOptions) { _options = options; _fallbackOptions = fallbackOptions; } - public CSharpAnalyzerOptionsProvider(AnalyzerConfigOptions options, AnalyzerOptions fallbackOptions) + public CSharpAnalyzerOptionsProvider(IOptionsReader options, AnalyzerOptions fallbackOptions) : this(options, fallbackOptions.GetIdeOptions()) { } @@ -101,7 +101,7 @@ internal CSharpCodeGenerationOptions GetCodeGenerationOptions() public CodeStyleOption2 PreferStaticLocalFunction => GetOption(CSharpCodeStyleOptions.PreferStaticLocalFunction, FallbackCodeStyleOptions.PreferStaticLocalFunction); private TValue GetOption(Option2 option, TValue defaultValue) - => _options.GetEditorConfigOption(option, defaultValue); + => _options.GetOption(option, defaultValue); private CSharpIdeCodeStyleOptions FallbackCodeStyleOptions => (CSharpIdeCodeStyleOptions?)_fallbackOptions.CodeStyleOptions ?? CSharpIdeCodeStyleOptions.Default; @@ -122,23 +122,29 @@ public static explicit operator CSharpAnalyzerOptionsProvider(AnalyzerOptionsPro => new(provider.GetAnalyzerConfigOptions(), provider.GetFallbackOptions()); public static implicit operator AnalyzerOptionsProvider(CSharpAnalyzerOptionsProvider provider) - => new(provider._options, provider._fallbackOptions); + => new(provider._options, LanguageNames.CSharp, provider._fallbackOptions); } internal static class CSharpAnalyzerOptionsProviders { + public static CSharpAnalyzerOptionsProvider GetCSharpAnalyzerOptions(this AnalyzerOptions options, SyntaxTree syntaxTree) + => new(options.AnalyzerConfigOptionsProvider.GetOptions(syntaxTree).GetOptionsReader(), options); + public static CSharpAnalyzerOptionsProvider GetCSharpAnalyzerOptions(this SemanticModelAnalysisContext context) - => new(context.Options.AnalyzerConfigOptionsProvider.GetOptions(context.SemanticModel.SyntaxTree), context.Options); + => GetCSharpAnalyzerOptions(context.Options, context.SemanticModel.SyntaxTree); public static CSharpAnalyzerOptionsProvider GetCSharpAnalyzerOptions(this SyntaxNodeAnalysisContext context) - => new(context.Options.AnalyzerConfigOptionsProvider.GetOptions(context.Node.SyntaxTree), context.Options); + => GetCSharpAnalyzerOptions(context.Options, context.Node.SyntaxTree); public static CSharpAnalyzerOptionsProvider GetCSharpAnalyzerOptions(this SyntaxTreeAnalysisContext context) - => new(context.Options.AnalyzerConfigOptionsProvider.GetOptions(context.Tree), context.Options); + => GetCSharpAnalyzerOptions(context.Options, context.Tree); public static CSharpAnalyzerOptionsProvider GetCSharpAnalyzerOptions(this CodeBlockAnalysisContext context) - => new(context.Options.AnalyzerConfigOptionsProvider.GetOptions(context.SemanticModel.SyntaxTree), context.Options); + => GetCSharpAnalyzerOptions(context.Options, context.SemanticModel.SyntaxTree); public static CSharpAnalyzerOptionsProvider GetCSharpAnalyzerOptions(this OperationAnalysisContext context) - => new(context.Options.AnalyzerConfigOptionsProvider.GetOptions(context.Operation.Syntax.SyntaxTree), context.Options); + => GetCSharpAnalyzerOptions(context.Options, context.Operation.Syntax.SyntaxTree); + + public static CSharpAnalyzerOptionsProvider GetCSharpAnalyzerOptions(this SymbolStartAnalysisContext context, SyntaxTree syntaxTree) + => GetCSharpAnalyzerOptions(context.Options, syntaxTree); } diff --git a/src/Analyzers/CSharp/Analyzers/MakeStructReadOnly/CSharpMakeStructReadOnlyDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/MakeStructReadOnly/CSharpMakeStructReadOnlyDiagnosticAnalyzer.cs index f45a33c471d9f..a62c8f1190346 100644 --- a/src/Analyzers/CSharp/Analyzers/MakeStructReadOnly/CSharpMakeStructReadOnlyDiagnosticAnalyzer.cs +++ b/src/Analyzers/CSharp/Analyzers/MakeStructReadOnly/CSharpMakeStructReadOnlyDiagnosticAnalyzer.cs @@ -9,6 +9,7 @@ using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.CSharp.MakeStructReadOnly; @@ -90,7 +91,7 @@ private static bool IsCandidate( if (typeDeclaration is null) return false; - var options = new CSharpAnalyzerOptionsProvider(context.Options.AnalyzerConfigOptionsProvider.GetOptions(typeDeclaration.SyntaxTree), context.Options); + var options = context.GetCSharpAnalyzerOptions(typeDeclaration.SyntaxTree); option = options.PreferReadOnlyStruct; if (!option.Value) return false; diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.cs.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.cs.xlf index 19d2e1f2fd3d8..aab53c1e3259a 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.cs.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.cs.xlf @@ -14,12 +14,12 @@ Blank line not allowed after arrow expression clause token - Blank line not allowed after arrow expression clause token + Za tokenem klauzule výrazu šipky není povolen prázdný řádek. Blank line not allowed after conditional expression token - Blank line not allowed after conditional expression token + Za tokenem podmíněného výrazu se nepovoluje prázdný řádek. @@ -229,47 +229,47 @@ Use block body for accessor - Use block body for accessor + Pro přístupové objekty používat text bloku. Use block body for constructor - Use block body for constructor + Pro konstruktory používat text bloku. Use block body for conversion operator - Use block body for conversion operator + Pro operátory převodu používat text bloku. Use block body for indexer - Use block body for indexer + Pro indexery používat text bloku. Use block body for lambda expression - Use block body for lambda expression + Pro lambda výrazy používat text bloku. Use block body for local function - Use block body for local function + Pro místní funkce používat text bloku. Use block body for method - Use block body for method + Pro metody používat text bloku. Use block body for operator - Use block body for operator + Pro operátory používat text bloku. Use block body for property - Use block body for property + Pro vlastnost použít text bloku. @@ -284,47 +284,47 @@ Use expression body for accessor - Use expression body for accessor + Pro přístupové objekty používat text výrazu. Use expression body for constructor - Use expression body for constructor + Pro konstruktory používat text výrazu. Use expression body for conversion operator - Use expression body for conversion operator + Pro operátory převodu používat text výrazu. Use expression body for indexer - Use expression body for indexer + Pro indexery používat text výrazu. Use expression body for lambda expression - Use expression body for lambda expression + Pro výrazy lambda používat text výrazu. Use expression body for local function - Use expression body for local function + Pro místní funkce používat text výrazu. Use expression body for method - Use expression body for method + Pro metody používat text výrazu. Use expression body for operator - Use expression body for operator + Pro operátory používat text výrazu. Use expression body for property - Use expression body for property + Pro vlastnosti používat text výrazu. @@ -359,7 +359,7 @@ Use 'nameof' - Use 'nameof' + Použít nameof diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.de.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.de.xlf index 9b36a2e1b0f79..abb6ed3c71997 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.de.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.de.xlf @@ -14,12 +14,12 @@ Blank line not allowed after arrow expression clause token - Blank line not allowed after arrow expression clause token + Nach dem Token der Pfeilausdrucksklausel ist keine leere Zeile zulässig Blank line not allowed after conditional expression token - Blank line not allowed after conditional expression token + Leere Zeile nach bedingtem Ausdruckstoken nicht zulässig @@ -229,47 +229,47 @@ Use block body for accessor - Use block body for accessor + Blocktextkörper für Zugriffsmethode verwenden Use block body for constructor - Use block body for constructor + Blocktextkörper für Konstruktor verwenden Use block body for conversion operator - Use block body for conversion operator + Blocktext für Konvertierungsoperator verwenden Use block body for indexer - Use block body for indexer + Blocktextkörper für Indexer verwenden Use block body for lambda expression - Use block body for lambda expression + Blocktextkörper für Lambdafunktion verwenden Use block body for local function - Use block body for local function + Blocktextkörper für lokale Funktion verwenden Use block body for method - Use block body for method + Blocktextkörper für Methode verwenden Use block body for operator - Use block body for operator + Blocktextkörper für Operator verwenden Use block body for property - Use block body for property + Blocktextkörper für Eigenschaft verwenden @@ -284,47 +284,47 @@ Use expression body for accessor - Use expression body for accessor + Ausdruckskörper für Zugriffsmethode verwenden Use expression body for constructor - Use expression body for constructor + Ausdruckskörper für Konstruktor verwenden Use expression body for conversion operator - Use expression body for conversion operator + Ausdruckstext für Konvertierungsoperator verwenden Use expression body for indexer - Use expression body for indexer + Ausdruckskörper für Indexer verwenden Use expression body for lambda expression - Use expression body for lambda expression + Ausdruckskörper für Lambdafunktion verwenden Use expression body for local function - Use expression body for local function + Ausdruckskörper für lokale Funktion verwenden Use expression body for method - Use expression body for method + Ausdruckskörper für Methode verwenden Use expression body for operator - Use expression body for operator + Ausdruckskörper für Operator verwenden Use expression body for property - Use expression body for property + Ausdruckskörper für Eigenschaft verwenden @@ -359,7 +359,7 @@ Use 'nameof' - Use 'nameof' + „nameof“ verwenden diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.es.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.es.xlf index 66f76ea0e6279..fc55bceb87baf 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.es.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.es.xlf @@ -14,12 +14,12 @@ Blank line not allowed after arrow expression clause token - Blank line not allowed after arrow expression clause token + No se permite una línea en blanco después del token de la cláusula de expresión de flecha Blank line not allowed after conditional expression token - Blank line not allowed after conditional expression token + No se permite una línea en blanco después del token de expresión condicional @@ -229,47 +229,47 @@ Use block body for accessor - Use block body for accessor + Usar cuerpo del bloque para el descriptor de acceso Use block body for constructor - Use block body for constructor + Usar cuerpo del bloque para el constructor Use block body for conversion operator - Use block body for conversion operator + Usar cuerpo del bloque para el operador de conversión Use block body for indexer - Use block body for indexer + Usar cuerpo del bloque para el indizador Use block body for lambda expression - Use block body for lambda expression + Usar cuerpo del bloque para la expresión lambda Use block body for local function - Use block body for local function + Usar cuerpo del bloque para la función local Use block body for method - Use block body for method + Usar cuerpo del bloque para el método Use block body for operator - Use block body for operator + Usar cuerpo del bloque para el operador Use block body for property - Use block body for property + Usar cuerpo del bloque para la propiedad @@ -284,47 +284,47 @@ Use expression body for accessor - Use expression body for accessor + Usar cuerpo de expresiones para el descriptor de acceso Use expression body for constructor - Use expression body for constructor + Usar cuerpo de expresiones para el constructor Use expression body for conversion operator - Use expression body for conversion operator + Usar cuerpo de expresiones para el operador de conversión Use expression body for indexer - Use expression body for indexer + Usar cuerpo de expresiones para los indizadores Use expression body for lambda expression - Use expression body for lambda expression + Usar cuerpo de expresiones para la expresión lambda Use expression body for local function - Use expression body for local function + Usar el cuerpo de expresiones para la función local Use expression body for method - Use expression body for method + Usar cuerpo de expresiones para el método Use expression body for operator - Use expression body for operator + Usar cuerpo de expresiones para el operador Use expression body for property - Use expression body for property + Usar cuerpo de expresiones para la propiedad @@ -359,7 +359,7 @@ Use 'nameof' - Use 'nameof' + Usar "nameof" diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.fr.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.fr.xlf index 4260ec122b402..f9f4876335ff0 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.fr.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.fr.xlf @@ -14,12 +14,12 @@ Blank line not allowed after arrow expression clause token - Blank line not allowed after arrow expression clause token + Ligne vide non autorisée après le jeton de clause d’expression fléchée Blank line not allowed after conditional expression token - Blank line not allowed after conditional expression token + Ligne vide non autorisée après un jeton d’expression conditionnelle @@ -229,47 +229,47 @@ Use block body for accessor - Use block body for accessor + Utiliser un corps de bloc pour un accesseur Use block body for constructor - Use block body for constructor + Utiliser un corps de bloc pour un constructeur Use block body for conversion operator - Use block body for conversion operator + Utiliser le corps de bloc pour un opérateur de conversion Use block body for indexer - Use block body for indexer + Utiliser un corps de bloc pour un indexeur Use block body for lambda expression - Use block body for lambda expression + Utiliser un corps de bloc pour une expression lambda Use block body for local function - Use block body for local function + Utiliser un corps de bloc pour une fonction locale Use block body for method - Use block body for method + Utiliser un corps de bloc pour une méthode Use block body for operator - Use block body for operator + Utiliser un corps de bloc pour un opérateur Use block body for property - Use block body for property + Utiliser un corps de bloc pour les propriétés @@ -284,47 +284,47 @@ Use expression body for accessor - Use expression body for accessor + Utiliser un corps d'expression pour un accesseur Use expression body for constructor - Use expression body for constructor + Utiliser un corps d'expression pour un constructeur Use expression body for conversion operator - Use expression body for conversion operator + Utiliser le corps d’expression pour un opérateur de conversion Use expression body for indexer - Use expression body for indexer + Utiliser un corps d'expression pour un indexeur Use expression body for lambda expression - Use expression body for lambda expression + Utiliser le corps d'expression pour une expression lambda Use expression body for local function - Use expression body for local function + Utiliser un corps d'expression pour une fonction locale Use expression body for method - Use expression body for method + Utiliser un corps d'expression pour une méthode Use expression body for operator - Use expression body for operator + Utiliser un corps d'expression pour un opérateur Use expression body for property - Use expression body for property + Utiliser un corps d'expression pour un propriété @@ -359,7 +359,7 @@ Use 'nameof' - Use 'nameof' + Utiliser « nameof » diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.it.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.it.xlf index 3f237e67b717a..5e686f4d5dc4a 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.it.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.it.xlf @@ -14,12 +14,12 @@ Blank line not allowed after arrow expression clause token - Blank line not allowed after arrow expression clause token + Riga vuota non consentita dopo il token della clausola dell'espressione arrow Blank line not allowed after conditional expression token - Blank line not allowed after conditional expression token + Riga vuota non consentita dopo il token di espressione condizionale @@ -229,47 +229,47 @@ Use block body for accessor - Use block body for accessor + Usare il corpo del blocco per la funzione di accesso Use block body for constructor - Use block body for constructor + Usare il corpo del blocco per il costruttore Use block body for conversion operator - Use block body for conversion operator + Usare il corpo del blocco per l'operatore di conversione Use block body for indexer - Use block body for indexer + Usare il corpo del blocco per l'indicizzatore Use block body for lambda expression - Use block body for lambda expression + Usare il corpo del blocco per l'espressione lambda Use block body for local function - Use block body for local function + Usare il corpo del blocco per la funzione locale Use block body for method - Use block body for method + Usare il corpo del blocco per il metodo Use block body for operator - Use block body for operator + Usare il corpo del blocco per l'operatore Use block body for property - Use block body for property + Usare il corpo del blocco per la proprietà @@ -284,47 +284,47 @@ Use expression body for accessor - Use expression body for accessor + Usare il corpo dell'espressione per la funzione di accesso Use expression body for constructor - Use expression body for constructor + Usare il corpo dell'espressione per il costruttore Use expression body for conversion operator - Use expression body for conversion operator + Usare il corpo dell'espressione per l'operatore di conversione Use expression body for indexer - Use expression body for indexer + Usare il corpo dell'espressione per l'indicizzatore Use expression body for lambda expression - Use expression body for lambda expression + Usare il corpo dell'espressione per l'espressione lambda Use expression body for local function - Use expression body for local function + Usare il corpo dell'espressione per la funzione locale Use expression body for method - Use expression body for method + Usare il corpo dell'espressione per il metodo Use expression body for operator - Use expression body for operator + Usare il corpo dell'espressione per l'operatore Use expression body for property - Use expression body for property + Usare il corpo dell'espressione per la proprietà @@ -359,7 +359,7 @@ Use 'nameof' - Use 'nameof' + Usare 'nameof' diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ja.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ja.xlf index debc64070dc4f..8de02dd62b704 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ja.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ja.xlf @@ -14,12 +14,12 @@ Blank line not allowed after arrow expression clause token - Blank line not allowed after arrow expression clause token + 矢印式句トークンの後に空白行は許可されていません Blank line not allowed after conditional expression token - Blank line not allowed after conditional expression token + 条件式トークンの後に空白行は許可されていません @@ -229,47 +229,47 @@ Use block body for accessor - Use block body for accessor + アクセサーにブロック本体を使用する Use block body for constructor - Use block body for constructor + コンストラクターにブロック本体を使用する Use block body for conversion operator - Use block body for conversion operator + 変換演算子にブロック本体を使用する Use block body for indexer - Use block body for indexer + インデクサーにブロック本体を使用する Use block body for lambda expression - Use block body for lambda expression + ラムダ式にブロック本体を使用する Use block body for local function - Use block body for local function + ローカル関数にブロック本体を使用する Use block body for method - Use block body for method + メソッドにブロック本体を使用する Use block body for operator - Use block body for operator + オペレーターにブロック本体を使用する Use block body for property - Use block body for property + プロパティにブロック本体を使用する @@ -284,47 +284,47 @@ Use expression body for accessor - Use expression body for accessor + アクセサーに式本体を使用する Use expression body for constructor - Use expression body for constructor + コンストラクターに式本体を使用する Use expression body for conversion operator - Use expression body for conversion operator + 変換演算子に式本体を使用する Use expression body for indexer - Use expression body for indexer + インデクサーに式本体を使用する Use expression body for lambda expression - Use expression body for lambda expression + ラムダ式に式本体を使用する Use expression body for local function - Use expression body for local function + ローカル関数に式本体を使用する Use expression body for method - Use expression body for method + メソッドに式本体を使用する Use expression body for operator - Use expression body for operator + オペレーターに式本体を使用する Use expression body for property - Use expression body for property + プロパティに式本体を使用する @@ -359,7 +359,7 @@ Use 'nameof' - Use 'nameof' + 'nameof' を使用する diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ko.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ko.xlf index 1b32b330bc3dd..568a3697af843 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ko.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ko.xlf @@ -14,12 +14,12 @@ Blank line not allowed after arrow expression clause token - Blank line not allowed after arrow expression clause token + 화살표 식 절 토큰 뒤에는 빈 줄을 사용할 수 없습니다. Blank line not allowed after conditional expression token - Blank line not allowed after conditional expression token + 조건식 토큰 다음에는 빈 줄을 사용할 수 없습니다. @@ -229,47 +229,47 @@ Use block body for accessor - Use block body for accessor + 접근자에 블록 본문 사용 Use block body for constructor - Use block body for constructor + 생성자에 블록 본문 사용 Use block body for conversion operator - Use block body for conversion operator + 변환 연산자에 블록 본문 사용 Use block body for indexer - Use block body for indexer + 인덱서에 블록 본문 사용 Use block body for lambda expression - Use block body for lambda expression + 람다 식에 블록 본문 사용 Use block body for local function - Use block body for local function + 로컬 함수에 블록 본문 사용 Use block body for method - Use block body for method + 메서드에 블록 본문 사용 Use block body for operator - Use block body for operator + 연산자에 블록 본문 사용 Use block body for property - Use block body for property + 속성에 블록 본문 사용 @@ -284,47 +284,47 @@ Use expression body for accessor - Use expression body for accessor + 접근자에 식 본문 사용 Use expression body for constructor - Use expression body for constructor + 생성자에 식 본문 사용 Use expression body for conversion operator - Use expression body for conversion operator + 변환 연산자에 식 본문 사용 Use expression body for indexer - Use expression body for indexer + 인덱서에 식 본문 사용 Use expression body for lambda expression - Use expression body for lambda expression + 람다 식에 식 본문 사용 Use expression body for local function - Use expression body for local function + 로컬 함수에 식 본문 사용 Use expression body for method - Use expression body for method + 메서드에 식 본문 사용 Use expression body for operator - Use expression body for operator + 연산자에 식 본문 사용 Use expression body for property - Use expression body for property + 속성에 식 본문 사용 diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pl.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pl.xlf index dfb10893c8a44..8798b4e06599b 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pl.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pl.xlf @@ -14,12 +14,12 @@ Blank line not allowed after arrow expression clause token - Blank line not allowed after arrow expression clause token + Pusty wiersz jest niedozwolony po tokenie klauzuli wyrażenia strzałki Blank line not allowed after conditional expression token - Blank line not allowed after conditional expression token + Pusty wiersz jest niedozwolony po tokenie wyrażenia warunkowego @@ -229,47 +229,47 @@ Use block body for accessor - Use block body for accessor + Użyj treści bloku dla metody dostępu Use block body for constructor - Use block body for constructor + Użyj treści bloku dla konstruktora Use block body for conversion operator - Use block body for conversion operator + Użyj treści bloku dla operatora konwersacji Use block body for indexer - Use block body for indexer + Użyj treści bloku dla indeksatora Use block body for lambda expression - Use block body for lambda expression + Użyj treści bloku dla wyrażenia lambda Use block body for local function - Use block body for local function + Użyj treści bloku dla funkcji lokalnej Use block body for method - Use block body for method + Użyj treści bloku dla metody Use block body for operator - Use block body for operator + Użyj treści bloku dla operatora Use block body for property - Use block body for property + Użyj treści bloku dla właściwości @@ -284,47 +284,47 @@ Use expression body for accessor - Use expression body for accessor + Użyj treści wyrażenia dla metody dostępu Use expression body for constructor - Use expression body for constructor + Użyj treści wyrażenia dla konstruktora Use expression body for conversion operator - Use expression body for conversion operator + Użyj treści wyrażenia dla operatora konwersji Use expression body for indexer - Use expression body for indexer + Użyj treści wyrażenia dla indeksatora Use expression body for lambda expression - Use expression body for lambda expression + Użyj treści wyrażenia dla wyrażenia lambda Use expression body for local function - Use expression body for local function + Użyj treści wyrażenia dla funkcji lokalnej Use expression body for method - Use expression body for method + Użyj treści wyrażenia dla metod Use expression body for operator - Use expression body for operator + Użyj treści wyrażenia dla operatora Use expression body for property - Use expression body for property + Użyj treści wyrażenia dla właściwości diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pt-BR.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pt-BR.xlf index 4c8eb5a4a66ba..a89f0da4ba1b8 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pt-BR.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pt-BR.xlf @@ -14,12 +14,12 @@ Blank line not allowed after arrow expression clause token - Blank line not allowed after arrow expression clause token + Linha em branco não permitida após token de cláusula de expressão de seta Blank line not allowed after conditional expression token - Blank line not allowed after conditional expression token + Linha em branco não permitida após token de expressão condicional @@ -229,47 +229,47 @@ Use block body for accessor - Use block body for accessor + Usar o corpo do bloco para acessador Use block body for constructor - Use block body for constructor + Usar o corpo do bloco para construtor Use block body for conversion operator - Use block body for conversion operator + Usar o corpo do bloco para operador de conversão Use block body for indexer - Use block body for indexer + Usar o corpo do bloco para indexador Use block body for lambda expression - Use block body for lambda expression + Usar o corpo do bloco para expressão lambda Use block body for local function - Use block body for local function + Usar o corpo do bloco para função local Use block body for method - Use block body for method + Usar o corpo do bloco para método Use block body for operator - Use block body for operator + Usar o corpo do bloco para operador Use block body for property - Use block body for property + Usar o corpo do bloco para propriedade @@ -284,47 +284,47 @@ Use expression body for accessor - Use expression body for accessor + Usar o corpo da expressão para acessador Use expression body for constructor - Use expression body for constructor + Usar o corpo da expressão para construtor Use expression body for conversion operator - Use expression body for conversion operator + Usar o corpo da expressão para operador de conversão Use expression body for indexer - Use expression body for indexer + Usar o corpo da expressão para indexador Use expression body for lambda expression - Use expression body for lambda expression + Usar o corpo da expressão para expressão lambda Use expression body for local function - Use expression body for local function + Usar o corpo da expressão para função local Use expression body for method - Use expression body for method + Usar o corpo da expressão para método Use expression body for operator - Use expression body for operator + Usar o corpo da expressão para operador Use expression body for property - Use expression body for property + Usar o corpo da expressão para propriedade @@ -359,7 +359,7 @@ Use 'nameof' - Use 'nameof' + Usar 'nameof' diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ru.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ru.xlf index 82c538f79bfa2..4ed2964792f05 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ru.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ru.xlf @@ -14,12 +14,12 @@ Blank line not allowed after arrow expression clause token - Blank line not allowed after arrow expression clause token + Пустая строка недопустима после маркера предложения выражения со стрелкой Blank line not allowed after conditional expression token - Blank line not allowed after conditional expression token + Пустая строка недопустима после маркера условного выражения @@ -229,47 +229,47 @@ Use block body for accessor - Use block body for accessor + Использовать тело блока для метода доступа Use block body for constructor - Use block body for constructor + Использовать тело блока для конструктора Use block body for conversion operator - Use block body for conversion operator + Использовать текст блока для оператора преобразования Use block body for indexer - Use block body for indexer + Использовать тело блока для индексатора Use block body for lambda expression - Use block body for lambda expression + Использовать тело блока для лямбда-выражения Use block body for local function - Use block body for local function + Использовать тело блока для локальной функции Use block body for method - Use block body for method + Использовать тело блока для метода Use block body for operator - Use block body for operator + Использовать тело блока для оператора Use block body for property - Use block body for property + Использовать тело блока для свойства @@ -284,47 +284,47 @@ Use expression body for accessor - Use expression body for accessor + Использовать тело выражения для метода доступа Use expression body for constructor - Use expression body for constructor + Использовать тело выражения для конструктора Use expression body for conversion operator - Use expression body for conversion operator + Использовать тело выражения для оператора преобразования Use expression body for indexer - Use expression body for indexer + Использовать тело выражения для индексатора Use expression body for lambda expression - Use expression body for lambda expression + Использовать тело выражения для лямбда-выражения Use expression body for local function - Use expression body for local function + Использовать тело выражения для локальной функции Use expression body for method - Use expression body for method + Использовать тело выражения для метода Use expression body for operator - Use expression body for operator + Использовать тело выражения для оператора Use expression body for property - Use expression body for property + Использовать тело выражения для свойства @@ -359,7 +359,7 @@ Use 'nameof' - Use 'nameof' + Использовать "nameof" diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.tr.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.tr.xlf index c34488fb300c0..788cff2c74a1a 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.tr.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.tr.xlf @@ -14,12 +14,12 @@ Blank line not allowed after arrow expression clause token - Blank line not allowed after arrow expression clause token + Ok ifadesi yan tümce belirtecinin ardından boş satıra izin verilmez Blank line not allowed after conditional expression token - Blank line not allowed after conditional expression token + Koşullu ifade belirtecinin ardından boş satıra izin verilmez @@ -229,47 +229,47 @@ Use block body for accessor - Use block body for accessor + Erişimci için blok gövdesi kullan Use block body for constructor - Use block body for constructor + Oluşturucu için blok gövdesi kullan Use block body for conversion operator - Use block body for conversion operator + Dönüştürme işleci için blok gövdesi kullan Use block body for indexer - Use block body for indexer + Dizin oluşturucu için blok gövdesi kullan Use block body for lambda expression - Use block body for lambda expression + Lambda ifadesi için blok gövdesi kullan Use block body for local function - Use block body for local function + Yerel işlev için blok gövdesi kullan Use block body for method - Use block body for method + Metot için blok gövdesi kullan Use block body for operator - Use block body for operator + İşleç için blok gövdesi kullan Use block body for property - Use block body for property + Özellikler için blok gövdesi kullan @@ -284,47 +284,47 @@ Use expression body for accessor - Use expression body for accessor + Erişimci için ifade gövdesi kullan Use expression body for constructor - Use expression body for constructor + Oluşturucu için ifade gövdesi kullan Use expression body for conversion operator - Use expression body for conversion operator + Dönüştürme işleci için ifade gövdesi kullan Use expression body for indexer - Use expression body for indexer + Dizin oluşturucu için ifade gövdesi kullan Use expression body for lambda expression - Use expression body for lambda expression + Lambda ifadesi için ifade gövdesi kullan Use expression body for local function - Use expression body for local function + Yerel işlev için ifade gövdesi kullan Use expression body for method - Use expression body for method + Metot için ifade gövdesi kullan Use expression body for operator - Use expression body for operator + İşleç için ifade gövdesi kullan Use expression body for property - Use expression body for property + Özellik için ifade gövdesi kullan @@ -359,7 +359,7 @@ Use 'nameof' - Use 'nameof' + “Nameof” kullan diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hans.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hans.xlf index 46c24928af936..752560c55bd57 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hans.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hans.xlf @@ -14,12 +14,12 @@ Blank line not allowed after arrow expression clause token - Blank line not allowed after arrow expression clause token + 箭头表达式子句标记后不允许空行 Blank line not allowed after conditional expression token - Blank line not allowed after conditional expression token + 条件表达式标记后不允许使用空行 @@ -229,47 +229,47 @@ Use block body for accessor - Use block body for accessor + 使用访问器的块主体 Use block body for constructor - Use block body for constructor + 使用构造函数的块主体 Use block body for conversion operator - Use block body for conversion operator + 使用块主体来表示转换运算符 Use block body for indexer - Use block body for indexer + 使用块主体来表示索引器 Use block body for lambda expression - Use block body for lambda expression + 使用块主体来表示 Lambda 表达式 Use block body for local function - Use block body for local function + 使用本地函数的块主体 Use block body for method - Use block body for method + 使用方法的程序块主体 Use block body for operator - Use block body for operator + 使用块主体来表示运算符 Use block body for property - Use block body for property + 使用属性的块主体 @@ -284,47 +284,47 @@ Use expression body for accessor - Use expression body for accessor + 使用访问器的表达式主体 Use expression body for constructor - Use expression body for constructor + 使用表达式主体来表示构造函数 Use expression body for conversion operator - Use expression body for conversion operator + 使用表达式主体来表示转换运算符 Use expression body for indexer - Use expression body for indexer + 使用索引器的表达式主体 Use expression body for lambda expression - Use expression body for lambda expression + 使用表达式主体来表示 Lambda 表达式 Use expression body for local function - Use expression body for local function + 使用本地函数的表达式主体 Use expression body for method - Use expression body for method + 使用表达式主体来表示方法 Use expression body for operator - Use expression body for operator + 使用表达式主体来表示运算符 Use expression body for property - Use expression body for property + 使用表达式主体来表示属性 @@ -359,7 +359,7 @@ Use 'nameof' - Use 'nameof' + 使用 "nameof" diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hant.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hant.xlf index 20130e8badc27..c423b3ad1f5db 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hant.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hant.xlf @@ -14,12 +14,12 @@ Blank line not allowed after arrow expression clause token - Blank line not allowed after arrow expression clause token + 在箭頭運算式子句權杖後不允許空白行 Blank line not allowed after conditional expression token - Blank line not allowed after conditional expression token + 條件運算式權杖之後不允許空白行 @@ -229,47 +229,47 @@ Use block body for accessor - Use block body for accessor + 使用存取子的區塊主體 Use block body for constructor - Use block body for constructor + 使用建構函式的區塊主體 Use block body for conversion operator - Use block body for conversion operator + 使用轉換運算子的區塊主體 Use block body for indexer - Use block body for indexer + 使用索引子的區塊主體 Use block body for lambda expression - Use block body for lambda expression + 使用 Lambda 運算式的區塊主體 Use block body for local function - Use block body for local function + 為區域函式使用區塊主體 Use block body for method - Use block body for method + 使用方法的區塊主體 Use block body for operator - Use block body for operator + 使用運算子的區塊主體 Use block body for property - Use block body for property + 使用屬性的區塊主體 @@ -284,47 +284,47 @@ Use expression body for accessor - Use expression body for accessor + 使用存取子的運算式主體 Use expression body for constructor - Use expression body for constructor + 使用建構函式的運算式主體 Use expression body for conversion operator - Use expression body for conversion operator + 使用轉換運算子的運算式主體 Use expression body for indexer - Use expression body for indexer + 使用索引子的運算式主體 Use expression body for lambda expression - Use expression body for lambda expression + 使用 Lambda 運算式的運算式主體 Use expression body for local function - Use expression body for local function + 為區域函式使用運算式主體 Use expression body for method - Use expression body for method + 使用方法的運算式主體 Use expression body for operator - Use expression body for operator + 使用運算子的運算式主體 Use expression body for property - Use expression body for property + 使用屬性的運算式主體 @@ -359,7 +359,7 @@ Use 'nameof' - Use 'nameof' + 使用 'nameof' diff --git a/src/Analyzers/CSharp/CodeFixes/UseNullPropagation/CSharpUseNullPropagationCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/UseNullPropagation/CSharpUseNullPropagationCodeFixProvider.cs index a002ac15201af..934510b97a7f4 100644 --- a/src/Analyzers/CSharp/CodeFixes/UseNullPropagation/CSharpUseNullPropagationCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/UseNullPropagation/CSharpUseNullPropagationCodeFixProvider.cs @@ -6,6 +6,7 @@ using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.UseNullPropagation; namespace Microsoft.CodeAnalysis.CSharp.UseNullPropagation @@ -32,6 +33,32 @@ public CSharpUseNullPropagationCodeFixProvider() { } + protected override bool TryGetBlock(SyntaxNode? statement, [NotNullWhen(true)] out StatementSyntax? block) + { + if (statement is BlockSyntax statementBlock) + { + block = statementBlock; + return true; + } + + block = null; + return false; + } + + protected override StatementSyntax ReplaceBlockStatements(StatementSyntax block, StatementSyntax newInnerStatement) + { + var newStatementList = SyntaxFactory.SingletonList(newInnerStatement); + return ((BlockSyntax)block).WithStatements(newStatementList); + } + + protected override SyntaxNode PostProcessElseIf(IfStatementSyntax ifStatement, StatementSyntax newWhenTrueStatement) + { + var elseClauseSyntax = (ElseClauseSyntax)ifStatement.Parent!; + return elseClauseSyntax + .WithElseKeyword(elseClauseSyntax.ElseKeyword.WithTrailingTrivia()) + .WithStatement(newWhenTrueStatement.WithPrependedLeadingTrivia(ifStatement.CloseParenToken.TrailingTrivia)); + } + protected override ElementBindingExpressionSyntax ElementBindingExpression(BracketedArgumentListSyntax argumentList) => SyntaxFactory.ElementBindingExpression(argumentList); } diff --git a/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.cs.xlf b/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.cs.xlf index 8647b015ee61c..67f2b7be5042c 100644 --- a/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.cs.xlf +++ b/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.cs.xlf @@ -79,7 +79,7 @@ Place token on following line - Place token on following line + Umístit token na následující řádek. diff --git a/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.de.xlf b/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.de.xlf index 8f6bbf1c1489c..4abc5b1355ca2 100644 --- a/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.de.xlf +++ b/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.de.xlf @@ -79,7 +79,7 @@ Place token on following line - Place token on following line + Token in der folgenden Zeile platzieren diff --git a/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.es.xlf b/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.es.xlf index 28ea617bfa787..9256720c61bfc 100644 --- a/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.es.xlf +++ b/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.es.xlf @@ -79,7 +79,7 @@ Place token on following line - Place token on following line + Colocar token en la línea siguiente diff --git a/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.fr.xlf b/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.fr.xlf index 6b62bcd2a77ea..3989d56110a41 100644 --- a/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.fr.xlf +++ b/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.fr.xlf @@ -79,7 +79,7 @@ Place token on following line - Place token on following line + Placer un jeton sur la ligne suivante diff --git a/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.it.xlf b/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.it.xlf index 3f1f4e6095a00..77b30f5576732 100644 --- a/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.it.xlf +++ b/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.it.xlf @@ -79,7 +79,7 @@ Place token on following line - Place token on following line + Inserisci il token nella riga seguente diff --git a/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.ja.xlf b/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.ja.xlf index be73b0b96ade8..7455f74abe2a6 100644 --- a/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.ja.xlf +++ b/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.ja.xlf @@ -79,7 +79,7 @@ Place token on following line - Place token on following line + 次の行にトークンを配置する diff --git a/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.ko.xlf b/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.ko.xlf index fa125a5737c2e..1186b6723ac1f 100644 --- a/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.ko.xlf +++ b/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.ko.xlf @@ -79,7 +79,7 @@ Place token on following line - Place token on following line + 다음 줄에 토큰 배치 diff --git a/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.pl.xlf b/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.pl.xlf index c9ab8bd4a5e0a..890e834074b1a 100644 --- a/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.pl.xlf +++ b/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.pl.xlf @@ -79,7 +79,7 @@ Place token on following line - Place token on following line + Umieść token w następnym wierszu diff --git a/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.pt-BR.xlf b/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.pt-BR.xlf index b25236548099c..48c6e7a04b5d2 100644 --- a/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.pt-BR.xlf +++ b/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.pt-BR.xlf @@ -79,7 +79,7 @@ Place token on following line - Place token on following line + Colocar token na linha a seguir diff --git a/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.ru.xlf b/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.ru.xlf index 72298b3919443..58513a85c773f 100644 --- a/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.ru.xlf +++ b/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.ru.xlf @@ -79,7 +79,7 @@ Place token on following line - Place token on following line + Поместите маркер на следующей строке diff --git a/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.tr.xlf b/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.tr.xlf index 31abe23a1e56e..b3a0bbd2e8e08 100644 --- a/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.tr.xlf +++ b/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.tr.xlf @@ -79,7 +79,7 @@ Place token on following line - Place token on following line + Belirteci aşağıdaki satıra yerleştir diff --git a/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.zh-Hans.xlf b/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.zh-Hans.xlf index a910db06002f3..346769480622b 100644 --- a/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.zh-Hans.xlf +++ b/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.zh-Hans.xlf @@ -79,7 +79,7 @@ Place token on following line - Place token on following line + 将令牌放置在以下行上 diff --git a/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.zh-Hant.xlf b/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.zh-Hant.xlf index c405dec26a227..4b02b6d7c6cfb 100644 --- a/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.zh-Hant.xlf +++ b/src/Analyzers/CSharp/CodeFixes/xlf/CSharpCodeFixesResources.zh-Hant.xlf @@ -79,7 +79,7 @@ Place token on following line - Place token on following line + 將權杖放在下一行 diff --git a/src/Analyzers/CSharp/Tests/Iterator/AddYieldTests.cs b/src/Analyzers/CSharp/Tests/Iterator/AddYieldTests.cs index ffc8a376e3623..6e168f328470d 100644 --- a/src/Analyzers/CSharp/Tests/Iterator/AddYieldTests.cs +++ b/src/Analyzers/CSharp/Tests/Iterator/AddYieldTests.cs @@ -2,28 +2,29 @@ // 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.CodeFixes; using Microsoft.CodeAnalysis.CSharp.CodeFixes.Iterator; -using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Testing; using Xunit; -using Xunit.Abstractions; namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics.Iterator { + using VerifyCS = CSharpCodeFixVerifier; + [Trait(Traits.Feature, Traits.Features.CodeActionsChangeToYield)] - public class AddYieldTests : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest + public class AddYieldTests { - public AddYieldTests(ITestOutputHelper logger) - : base(logger) + private static async Task TestMissingInRegularAndScriptAsync(string code) { + await VerifyCS.VerifyCodeFixAsync(code, code); } - internal override (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProviderAndFixer(Workspace workspace) - => (null, new CSharpAddYieldCodeFixProvider()); + private static async Task TestInRegularAndScriptAsync(string code, string fixedCode) + { + await VerifyCS.VerifyCodeFixAsync(code, fixedCode); + } [Fact] public async Task TestAddYieldIEnumerableReturnNull() @@ -36,7 +37,7 @@ class Program { static IEnumerable M() { - [|return null|]; + return null; } }"; await TestMissingInRegularAndScriptAsync(initial); @@ -53,7 +54,7 @@ class Program { static IEnumerable M() { - [|return new object()|]; + return {|CS0266:new object()|}; } }"; var expected = @@ -81,7 +82,7 @@ class Program { static IEnumerator M() { - [|return new object()|]; + return {|CS0266:new object()|}; } }"; var expected = @@ -110,7 +111,7 @@ class Program { static IEnumerator M() { - [|return new List()|]; + return {|CS0266:new List()|}; } }"; var expected = @@ -140,7 +141,7 @@ class Program { static IEnumerator M() { - [|return new object()|]; + return {|CS0266:new object()|}; } }"; var expected = @@ -170,7 +171,7 @@ class Program { static IEnumerable M() { - [|return new object()|]; + return {|CS0266:new object()|}; } }"; var expected = @@ -200,7 +201,7 @@ class Program { static IEnumerable M() { - [|return new List()|]; + return new List(); } }"; await TestMissingInRegularAndScriptAsync(initial); @@ -218,7 +219,7 @@ class Program { static IEnumerator M() { - [|return default(T)|]; + return {|CS0266:default(T)|}; } }"; var expected = @@ -248,7 +249,7 @@ class Program { static IEnumerable M() { - [|return 0|]; + return {|CS0029:0|}; } }"; var expected = @@ -278,7 +279,7 @@ class Program { static IEnumerator M() { - [|return 0|]; + return {|CS0029:0|}; } }"; var expected = @@ -308,7 +309,7 @@ class Program { static IEnumerator> M() { - [|return new List()|]; + return {|CS0266:new List()|}; } }"; await TestMissingInRegularAndScriptAsync(initial); @@ -326,7 +327,7 @@ class Program { static IEnumerator> M() { - [|return new List()|]; + return {|CS0266:new List()|}; } }"; var expected = @@ -374,13 +375,13 @@ static void Main(string[] args) public class B : A> where Y : new() { - public override A.B P1 { get; set; } - public virtual Y P2 { get { [|return new Z()|]; } } + public override A.B P1 { get; {|CS0546:set|}; } + public virtual Y P2 { get { return {|CS0029:new Z()|}; } } public class C : B> where X : new() { public override A.B>.B.B.C> P1 { get; set; } - public override A.B.C P2 { get; set; } + public override A.B.C P2 { get; {|CS0546:set|}; } public virtual X P3 { get; set; } public class D : C> where W : new() diff --git a/src/Analyzers/CSharp/Tests/UseNullPropagation/UseNullPropagationTests.cs b/src/Analyzers/CSharp/Tests/UseNullPropagation/UseNullPropagationTests.cs index 9a7a2a84426fe..657f652db904f 100644 --- a/src/Analyzers/CSharp/Tests/UseNullPropagation/UseNullPropagationTests.cs +++ b/src/Analyzers/CSharp/Tests/UseNullPropagation/UseNullPropagationTests.cs @@ -2069,5 +2069,137 @@ class C Action M(List p) => p is null ? null : p.Add; }"); } + + [Fact, WorkItem(66036, "https://github.com/dotnet/roslyn/issues/66036")] + public async Task TestElseIfStatement1() + { + await TestInRegularAndScript1Async(""" + class C + { + void M(string s) + { + if (true) + { + } + else [|if|] (s != null) + { + s.ToString(); + } + } + } + """, """ + class C + { + void M(string s) + { + if (true) + { + } + else + { + s?.ToString(); + } + } + } + """); + } + + [Fact, WorkItem(66036, "https://github.com/dotnet/roslyn/issues/66036")] + public async Task TestElseIfStatement2() + { + await TestInRegularAndScript1Async(""" + class C + { + void M(string s) + { + if (true) + { + } + else [|if|] (s != null) + s.ToString(); + } + } + """, """ + class C + { + void M(string s) + { + if (true) + { + } + else + s?.ToString(); + } + } + """); + } + + [Fact, WorkItem(66036, "https://github.com/dotnet/roslyn/issues/66036")] + public async Task TestElseIfStatement_Trivia() + { + await TestInRegularAndScript1Async(""" + class C + { + void M(string s) + { + if (true) + { + } + else [|if|] (s != null) + { + // comment + s.ToString(); + } + } + } + """, """ + class C + { + void M(string s) + { + if (true) + { + } + else + { + // comment + s?.ToString(); + } + } + } + """); + } + + [Fact, WorkItem(66036, "https://github.com/dotnet/roslyn/issues/66036")] + public async Task TestElseIfStatement_KeepBracePlacementStyle() + { + await TestInRegularAndScript1Async(""" + class C + { + void M(string s) + { + if (true) + { + } + else [|if|] (s != null) { + s.ToString(); + } + } + } + """, """ + class C + { + void M(string s) + { + if (true) + { + } + else { + s?.ToString(); + } + } + } + """); + } } } diff --git a/src/Analyzers/Core/Analyzers/AbstractBuiltInCodeStyleDiagnosticAnalyzer.cs b/src/Analyzers/Core/Analyzers/AbstractBuiltInCodeStyleDiagnosticAnalyzer.cs index c45c582f811d3..bea7a1a74c77c 100644 --- a/src/Analyzers/Core/Analyzers/AbstractBuiltInCodeStyleDiagnosticAnalyzer.cs +++ b/src/Analyzers/Core/Analyzers/AbstractBuiltInCodeStyleDiagnosticAnalyzer.cs @@ -22,8 +22,8 @@ internal abstract partial class AbstractBuiltInCodeStyleDiagnosticAnalyzer /// Diagnostic ID reported by this analyzer /// Build enforcement recommendation for this analyzer /// - /// Code style option that can be used to configure the given . - /// , if there is no such unique option. + /// Code style editorconfig option that can be used to configure the given . + /// , if there is no such option that can be set in an editorconfig. /// /// Title for the diagnostic descriptor /// @@ -52,7 +52,7 @@ protected AbstractBuiltInCodeStyleDiagnosticAnalyzer( /// Diagnostic ID reported by this analyzer /// Build enforcement recommendation for this analyzer /// - /// Set of two or more code style options that can be used to configure the diagnostic severity of the given diagnosticId. + /// Set of two or more code style editorconfig options that can be used to configure the diagnostic severity of the given diagnosticId. /// /// Title for the diagnostic descriptor /// @@ -77,7 +77,7 @@ protected AbstractBuiltInCodeStyleDiagnosticAnalyzer( } /// - /// Constructor for a code style analyzer with a multiple diagnostic descriptors with a code style option that can be used to configure each descriptor. + /// Constructor for a code style analyzer with a multiple diagnostic descriptors with a code style editorconfig option that can be used to configure each descriptor. /// protected AbstractBuiltInCodeStyleDiagnosticAnalyzer(ImmutableDictionary supportedDiagnosticsWithOptions) : this(supportedDiagnosticsWithOptions.Keys.ToImmutableArray()) @@ -87,7 +87,7 @@ protected AbstractBuiltInCodeStyleDiagnosticAnalyzer(ImmutableDictionary - /// Constructor for a code style analyzer with multiple diagnostic descriptors with zero or more code style options that can be used to configure each descriptor. + /// Constructor for a code style analyzer with multiple diagnostic descriptors with zero or more code style editorconfig options that can be used to configure each descriptor. /// protected AbstractBuiltInCodeStyleDiagnosticAnalyzer(ImmutableDictionary> supportedDiagnosticsWithOptions) : this(supportedDiagnosticsWithOptions.Keys.ToImmutableArray()) diff --git a/src/Analyzers/Core/Analyzers/AnalyzerOptionsProvider.cs b/src/Analyzers/Core/Analyzers/AnalyzerOptionsProvider.cs index 2f576b49d543c..ede8a9385965a 100644 --- a/src/Analyzers/Core/Analyzers/AnalyzerOptionsProvider.cs +++ b/src/Analyzers/Core/Analyzers/AnalyzerOptionsProvider.cs @@ -24,21 +24,24 @@ internal readonly struct AnalyzerOptionsProvider /// /// Document editorconfig options. /// - private readonly AnalyzerConfigOptions _options; + private readonly IOptionsReader _options; /// /// Fallback options - the default options in Code Style layer. /// private readonly IdeAnalyzerOptions _fallbackOptions; - public AnalyzerOptionsProvider(AnalyzerConfigOptions options, IdeAnalyzerOptions fallbackOptions) + private readonly string _language; + + public AnalyzerOptionsProvider(IOptionsReader options, string language, IdeAnalyzerOptions fallbackOptions) { _options = options; + _language = language; _fallbackOptions = fallbackOptions; } - public AnalyzerOptionsProvider(AnalyzerConfigOptions options, AnalyzerOptions fallbackOptions) - : this(options, fallbackOptions.GetIdeOptions()) + public AnalyzerOptionsProvider(IOptionsReader options, string language, AnalyzerOptions fallbackOptions) + : this(options, language, fallbackOptions.GetIdeOptions()) { } @@ -96,10 +99,10 @@ public SyntaxFormattingOptions GetSyntaxFormattingOptions(ISyntaxFormatting form public string FileHeaderTemplate => GetOption(CodeStyleOptions2.FileHeaderTemplate, defaultValue: string.Empty); // no fallback IDE option private TValue GetOption(Option2 option, TValue defaultValue) - => _options.GetEditorConfigOption(option, defaultValue); + => _options.GetOption(option, defaultValue); private TValue GetOption(PerLanguageOption2 option, TValue defaultValue) - => _options.GetEditorConfigOption(option, defaultValue); + => _options.GetOption(option, _language, defaultValue); private IdeCodeStyleOptions.CommonOptions FallbackCodeStyleOptions => _fallbackOptions.CodeStyleOptions?.Common ?? IdeCodeStyleOptions.CommonOptions.Default; @@ -107,7 +110,7 @@ private IdeCodeStyleOptions.CommonOptions FallbackCodeStyleOptions private SimplifierOptions.CommonOptions FallbackSimplifierOptions => _fallbackOptions.CleanupOptions?.SimplifierOptions.Common ?? SimplifierOptions.CommonOptions.Default; - internal AnalyzerConfigOptions GetAnalyzerConfigOptions() + internal IOptionsReader GetAnalyzerConfigOptions() => _options; internal IdeAnalyzerOptions GetFallbackOptions() @@ -124,22 +127,22 @@ public static IdeAnalyzerOptions GetIdeOptions(this AnalyzerOptions options) #endif public static AnalyzerOptionsProvider GetAnalyzerOptions(this AnalyzerOptions analyzerOptions, SyntaxTree syntaxTree) - => new(analyzerOptions.AnalyzerConfigOptionsProvider.GetOptions(syntaxTree), analyzerOptions); + => new(analyzerOptions.AnalyzerConfigOptionsProvider.GetOptions(syntaxTree).GetOptionsReader(), syntaxTree.Options.Language, analyzerOptions); public static AnalyzerOptionsProvider GetAnalyzerOptions(this SemanticModelAnalysisContext context) - => new(context.Options.AnalyzerConfigOptionsProvider.GetOptions(context.SemanticModel.SyntaxTree), context.Options); + => GetAnalyzerOptions(context.Options, context.SemanticModel.SyntaxTree); public static AnalyzerOptionsProvider GetAnalyzerOptions(this SyntaxNodeAnalysisContext context) - => new(context.Options.AnalyzerConfigOptionsProvider.GetOptions(context.Node.SyntaxTree), context.Options); + => GetAnalyzerOptions(context.Options, context.Node.SyntaxTree); public static AnalyzerOptionsProvider GetAnalyzerOptions(this SyntaxTreeAnalysisContext context) - => new(context.Options.AnalyzerConfigOptionsProvider.GetOptions(context.Tree), context.Options); + => GetAnalyzerOptions(context.Options, context.Tree); public static AnalyzerOptionsProvider GetAnalyzerOptions(this OperationAnalysisContext context) - => new(context.Options.AnalyzerConfigOptionsProvider.GetOptions(context.Operation.Syntax.SyntaxTree), context.Options); + => GetAnalyzerOptions(context.Options, context.Operation.Syntax.SyntaxTree); public static AnalyzerOptionsProvider GetAnalyzerOptions(this CodeBlockAnalysisContext context) - => new(context.Options.AnalyzerConfigOptionsProvider.GetOptions(context.CodeBlock.SyntaxTree), context.Options); + => GetAnalyzerOptions(context.Options, context.CodeBlock.SyntaxTree); public static IdeAnalyzerOptions GetIdeAnalyzerOptions(this SemanticModelAnalysisContext context) => context.Options.GetIdeOptions(); diff --git a/src/Analyzers/Core/Analyzers/IDEDiagnosticIdToOptionMappingHelper.cs b/src/Analyzers/Core/Analyzers/IDEDiagnosticIdToOptionMappingHelper.cs index 35ef514e28dc5..d13318e87dfae 100644 --- a/src/Analyzers/Core/Analyzers/IDEDiagnosticIdToOptionMappingHelper.cs +++ b/src/Analyzers/Core/Analyzers/IDEDiagnosticIdToOptionMappingHelper.cs @@ -49,7 +49,7 @@ public static void AddOptionMapping(string diagnosticId, ImmutableHashSet().Single().GetKeyNameForLanguage(null).Contains("%LANGUAGE%")); - } - else if (option is ISingleValuedOption singleValuedOption) - { - Debug.Assert(option.StorageLocations.OfType().Single() is { } editorConfigLocation && - ( - (singleValuedOption.LanguageName is null && (editorConfigLocation.KeyName.StartsWith("dotnet_") || editorConfigLocation.KeyName == "file_header_template")) || - (singleValuedOption.LanguageName == LanguageNames.CSharp && editorConfigLocation.KeyName.StartsWith("csharp_")) || - (singleValuedOption.LanguageName == LanguageNames.VisualBasic && editorConfigLocation.KeyName.StartsWith("visual_basic_")) - ) - ); - } - else - { - Debug.Fail("Unexpected option type."); - } - } -#endif + Debug.Assert(options.All(option => option.Definition.IsEditorConfigOption)); map.TryAdd(diagnosticId, options); } diff --git a/src/Analyzers/Core/Analyzers/UseSystemHashCode/UseSystemHashCodeDiagnosticAnalyzer.cs b/src/Analyzers/Core/Analyzers/UseSystemHashCode/UseSystemHashCodeDiagnosticAnalyzer.cs index 30e2df677101d..9c9d39f83095f 100644 --- a/src/Analyzers/Core/Analyzers/UseSystemHashCode/UseSystemHashCodeDiagnosticAnalyzer.cs +++ b/src/Analyzers/Core/Analyzers/UseSystemHashCode/UseSystemHashCodeDiagnosticAnalyzer.cs @@ -16,7 +16,7 @@ internal class UseSystemHashCodeDiagnosticAnalyzer : AbstractBuiltInCodeStyleDia public UseSystemHashCodeDiagnosticAnalyzer() : base(IDEDiagnosticIds.UseSystemHashCode, EnforceOnBuildValues.UseSystemHashCode, - CodeStyleOptions2.PreferSystemHashCode, + option: null, new LocalizableResourceString(nameof(AnalyzersResources.Use_System_HashCode), AnalyzersResources.ResourceManager, typeof(AnalyzersResources)), new LocalizableResourceString(nameof(AnalyzersResources.GetHashCode_implementation_can_be_simplified), AnalyzersResources.ResourceManager, typeof(AnalyzersResources))) { diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.cs.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.cs.xlf index d1da8af25e3aa..12be2edb8ab0e 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.cs.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.cs.xlf @@ -264,7 +264,7 @@ Remove accessibility modifiers - Remove accessibility modifiers + Odebrat modifikátory přístupnosti @@ -329,7 +329,7 @@ Simplify check - Simplify check + Zjednodušit kontrolu diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.de.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.de.xlf index d1f304887e4cb..c0c81acd80f5d 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.de.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.de.xlf @@ -264,7 +264,7 @@ Remove accessibility modifiers - Remove accessibility modifiers + Barrierefreiheitsmodifizierer entfernen @@ -329,7 +329,7 @@ Simplify check - Simplify check + Überprüfung vereinfachen diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.es.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.es.xlf index 381e4fc64cd1f..1dab8b8ce0b05 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.es.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.es.xlf @@ -264,7 +264,7 @@ Remove accessibility modifiers - Remove accessibility modifiers + Quitar modificadores de accesibilidad @@ -329,7 +329,7 @@ Simplify check - Simplify check + Simplificar comprobación diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.fr.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.fr.xlf index b7229e635b993..1f7ce6e176138 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.fr.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.fr.xlf @@ -264,7 +264,7 @@ Remove accessibility modifiers - Remove accessibility modifiers + Supprimer des modificateurs d'accessibilité @@ -329,7 +329,7 @@ Simplify check - Simplify check + Simplifier la vérification diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.it.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.it.xlf index f221c03a0b0a5..9306efc27203f 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.it.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.it.xlf @@ -264,7 +264,7 @@ Remove accessibility modifiers - Remove accessibility modifiers + Rimuovi modificatori di accessibilità @@ -329,7 +329,7 @@ Simplify check - Simplify check + Semplifica il controllo diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.ja.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.ja.xlf index 2fe71f99b4a30..36577b2a7d4bd 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.ja.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.ja.xlf @@ -264,7 +264,7 @@ Remove accessibility modifiers - Remove accessibility modifiers + アクセシビリティ修飾子を削除する @@ -329,7 +329,7 @@ Simplify check - Simplify check + チェックの簡略化 diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.ko.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.ko.xlf index e25eb1ea7b294..3640249d7da74 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.ko.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.ko.xlf @@ -264,7 +264,7 @@ Remove accessibility modifiers - Remove accessibility modifiers + 접근성 한정자 제거 @@ -329,7 +329,7 @@ Simplify check - Simplify check + 검사 단순화 diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.pl.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.pl.xlf index ed998e346cb05..a52bd4f1e65f0 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.pl.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.pl.xlf @@ -264,7 +264,7 @@ Remove accessibility modifiers - Remove accessibility modifiers + Usuń modyfikatory ułatwień dostępu @@ -329,7 +329,7 @@ Simplify check - Simplify check + Uprość kontrolę diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.pt-BR.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.pt-BR.xlf index 422ed515ca75a..483beb3e85420 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.pt-BR.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.pt-BR.xlf @@ -264,7 +264,7 @@ Remove accessibility modifiers - Remove accessibility modifiers + Remover modificadores de acessibilidade @@ -329,7 +329,7 @@ Simplify check - Simplify check + Simplificar a verificação diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.ru.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.ru.xlf index 42a55a4fa54e3..90548d064d0a1 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.ru.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.ru.xlf @@ -264,7 +264,7 @@ Remove accessibility modifiers - Remove accessibility modifiers + Удалить модификаторы доступа @@ -329,7 +329,7 @@ Simplify check - Simplify check + Упростить проверку diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.tr.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.tr.xlf index b11597a63a397..9dd7aaa35b7ad 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.tr.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.tr.xlf @@ -264,7 +264,7 @@ Remove accessibility modifiers - Remove accessibility modifiers + Erişilebilirlik değiştiricilerini kaldır @@ -329,7 +329,7 @@ Simplify check - Simplify check + Denetimi basitleştir diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.zh-Hans.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.zh-Hans.xlf index 0536b7157bff6..7ded05062a88b 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.zh-Hans.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.zh-Hans.xlf @@ -264,7 +264,7 @@ Remove accessibility modifiers - Remove accessibility modifiers + 删除辅助功能修饰符 @@ -329,7 +329,7 @@ Simplify check - Simplify check + 简化检查 diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.zh-Hant.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.zh-Hant.xlf index 64999c219b32b..3ee53e76fea0a 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.zh-Hant.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.zh-Hant.xlf @@ -264,7 +264,7 @@ Remove accessibility modifiers - Remove accessibility modifiers + 移除協助工具修飾元 @@ -329,7 +329,7 @@ Simplify check - Simplify check + 簡化檢查 diff --git a/src/Analyzers/Core/CodeFixes/AnalyzerOptionsProviders.cs b/src/Analyzers/Core/CodeFixes/AnalyzerOptionsProviders.cs index e271583f87f08..c799a31e569e9 100644 --- a/src/Analyzers/Core/CodeFixes/AnalyzerOptionsProviders.cs +++ b/src/Analyzers/Core/CodeFixes/AnalyzerOptionsProviders.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using System.Text; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.Diagnostics; @@ -17,8 +18,8 @@ public static async ValueTask GetAnalyzerOptionsProvide { var syntaxTree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var analyzerOptions = document.Project.AnalyzerOptions; - var configOptions = analyzerOptions.AnalyzerConfigOptionsProvider.GetOptions(syntaxTree); + var configOptions = analyzerOptions.AnalyzerConfigOptionsProvider.GetOptions(syntaxTree).GetOptionsReader(); - return new AnalyzerOptionsProvider(configOptions, analyzerOptions); + return new AnalyzerOptionsProvider(configOptions, document.Project.Language, analyzerOptions); } } diff --git a/src/Analyzers/Core/CodeFixes/UseNullPropagation/AbstractUseNullPropagationCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/UseNullPropagation/AbstractUseNullPropagationCodeFixProvider.cs index 922b904539cf0..4bb65d0e6fc7e 100644 --- a/src/Analyzers/Core/CodeFixes/UseNullPropagation/AbstractUseNullPropagationCodeFixProvider.cs +++ b/src/Analyzers/Core/CodeFixes/UseNullPropagation/AbstractUseNullPropagationCodeFixProvider.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Immutable; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -47,6 +48,9 @@ internal abstract class AbstractUseNullPropagationCodeFixProvider< where TExpressionStatementSyntax : TStatementSyntax where TElementBindingArgumentListSyntax : SyntaxNode { + protected abstract bool TryGetBlock(SyntaxNode? node, [NotNullWhen(true)] out TStatementSyntax? block); + protected abstract TStatementSyntax ReplaceBlockStatements(TStatementSyntax block, TStatementSyntax newInnerStatement); + protected abstract SyntaxNode PostProcessElseIf(TIfStatementSyntax ifStatement, TStatementSyntax newWhenTrueStatement); protected abstract TElementBindingExpressionSyntax ElementBindingExpression(TElementBindingArgumentListSyntax argumentList); public override ImmutableArray FixableDiagnosticIds @@ -142,17 +146,40 @@ private void FixIfStatement( var syntaxFacts = document.GetRequiredLanguageService(); var generator = document.GetRequiredLanguageService(); - var whenTrueStatement = (TExpressionStatementSyntax)root.FindNode(diagnostic.AdditionalLocations[1].SourceSpan); + var whenTrueStatement = (TStatementSyntax)root.FindNode(diagnostic.AdditionalLocations[1].SourceSpan); var match = (TExpressionSyntax)root.FindNode(diagnostic.AdditionalLocations[2].SourceSpan, getInnermostNodeForTie: true); var whenPartIsNullable = diagnostic.Properties.ContainsKey(UseNullPropagationConstants.WhenPartIsNullable); + SyntaxNode nodeToBeReplaced = ifStatement; + SyntaxNode? replacementNode = null; + // we have `if (x != null) x.Y();`. Update `x.Y()` to be `x?.Y()`, then replace the entire // if-statement with that expression statement. var newWhenTrueStatement = CreateConditionalAccessExpression( syntaxFacts, generator, whenPartIsNullable, whenTrueStatement, match); Contract.ThrowIfNull(newWhenTrueStatement); + var isElseIf = syntaxFacts.IsElseClause(ifStatement.Parent); + + // If we have code like: + // ... + // else if (v != null) + // { + // v.M(); + // } + // then we want to keep the result statement in a block: + // else + // { + // v?.M(); + // } + // Applies only to C# since VB doesn't have a general-purpose block syntax + if (isElseIf && + TryGetBlock(whenTrueStatement.Parent, out var block)) + { + newWhenTrueStatement = ReplaceBlockStatements(block, newWhenTrueStatement); + } + // If there's leading trivia on the original inner statement, then combine that with the leading // trivia on the if-statement. We'll need to add a formatting annotation so that the leading comments // are put in the right location. @@ -164,15 +191,23 @@ private void FixIfStatement( } else { - newWhenTrueStatement = newWhenTrueStatement.WithLeadingTrivia(ifStatement.GetLeadingTrivia()); + if (isElseIf) + { + nodeToBeReplaced = ifStatement.Parent!; + replacementNode = PostProcessElseIf(ifStatement, newWhenTrueStatement); + } + else + { + newWhenTrueStatement = newWhenTrueStatement.WithLeadingTrivia(ifStatement.GetLeadingTrivia()); + } } // If there's trailing comments on the original inner statement, then preserve that. Otherwise, // replace it with the trailing trivia of hte original if-statement. - if (!newWhenTrueStatement.GetTrailingTrivia().Any(syntaxFacts.IsRegularComment)) + if (!newWhenTrueStatement.GetTrailingTrivia().Any(syntaxFacts.IsRegularComment) && !isElseIf) newWhenTrueStatement = newWhenTrueStatement.WithTrailingTrivia(ifStatement.GetTrailingTrivia()); - editor.ReplaceNode(ifStatement, newWhenTrueStatement); + editor.ReplaceNode(nodeToBeReplaced, replacementNode ?? newWhenTrueStatement); } private TContainer? CreateConditionalAccessExpression( diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.cs.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.cs.xlf index 90f73c88d65f9..bb71810fa020b 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.cs.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.cs.xlf @@ -44,7 +44,7 @@ Fix name violation: {0} - Fix name violation: {0} + Opravit porušení názvu: {0} @@ -59,7 +59,7 @@ Make type partial - Make type partial + Nastavit typ jako částečný @@ -74,7 +74,7 @@ Suppress or configure issues - Suppress or configure issues + Potlačit nebo konfigurovat problémy diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.de.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.de.xlf index 5d8e913806f8a..bf2a4d2da3c5e 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.de.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.de.xlf @@ -44,7 +44,7 @@ Fix name violation: {0} - Fix name violation: {0} + Namensverletzung beheben: {0} @@ -59,7 +59,7 @@ Make type partial - Make type partial + Typ als partiell festlegen @@ -74,7 +74,7 @@ Suppress or configure issues - Suppress or configure issues + Issues unterdrücken oder konfigurieren diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.es.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.es.xlf index a92c942f03a1e..38df8a3a6fe4a 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.es.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.es.xlf @@ -44,7 +44,7 @@ Fix name violation: {0} - Fix name violation: {0} + Corregir infracción de nombre: {0} @@ -59,7 +59,7 @@ Make type partial - Make type partial + Convertir el tipo en parcial @@ -74,7 +74,7 @@ Suppress or configure issues - Suppress or configure issues + Suprimir o configurar incidencias diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.fr.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.fr.xlf index 70c9763d69293..3c9f2dcc4f1e3 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.fr.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.fr.xlf @@ -44,7 +44,7 @@ Fix name violation: {0} - Fix name violation: {0} + Corrigez la violation de nom : {0} @@ -59,7 +59,7 @@ Make type partial - Make type partial + Rendre le type partiel @@ -74,7 +74,7 @@ Suppress or configure issues - Suppress or configure issues + Supprimer ou configurer des problèmes diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.it.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.it.xlf index 967bdb027dd14..6663cc70405a8 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.it.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.it.xlf @@ -44,7 +44,7 @@ Fix name violation: {0} - Fix name violation: {0} + Correggi violazione del nome: {0} @@ -59,7 +59,7 @@ Make type partial - Make type partial + Rendere il tipo parziale @@ -74,7 +74,7 @@ Suppress or configure issues - Suppress or configure issues + Elimina o configura i problemi diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ja.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ja.xlf index 94765e1963512..7777032722baf 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ja.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ja.xlf @@ -44,7 +44,7 @@ Fix name violation: {0} - Fix name violation: {0} + 名前の違反を修正します: {0} @@ -59,7 +59,7 @@ Make type partial - Make type partial + 型を部分的にする @@ -74,7 +74,7 @@ Suppress or configure issues - Suppress or configure issues + 問題の抑制または構成 diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ko.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ko.xlf index 7b1b9ec09a40d..77f1ec820f269 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ko.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ko.xlf @@ -44,7 +44,7 @@ Fix name violation: {0} - Fix name violation: {0} + 이름 위반 수정: {0} @@ -74,7 +74,7 @@ Suppress or configure issues - Suppress or configure issues + 문제 표시 안 함 또는 구성 diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.pl.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.pl.xlf index d8f64da86acb1..fe8b73e0f777a 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.pl.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.pl.xlf @@ -44,7 +44,7 @@ Fix name violation: {0} - Fix name violation: {0} + Rozwiąż problem z naruszeniem nazwy: {0} @@ -74,7 +74,7 @@ Suppress or configure issues - Suppress or configure issues + Problemy z pomijaniem lub konfigurowaniem diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.pt-BR.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.pt-BR.xlf index c976e8184664a..1d8b57979bd58 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.pt-BR.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.pt-BR.xlf @@ -44,7 +44,7 @@ Fix name violation: {0} - Fix name violation: {0} + Corrigir violação de nome: {0} @@ -59,7 +59,7 @@ Make type partial - Make type partial + Tornar o tipo parcial @@ -74,7 +74,7 @@ Suppress or configure issues - Suppress or configure issues + Suprimir ou configurar problemas diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ru.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ru.xlf index 1fb80684aa821..ababee4a104ee 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ru.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ru.xlf @@ -44,7 +44,7 @@ Fix name violation: {0} - Fix name violation: {0} + Устраните нарушение имени: {0} @@ -59,7 +59,7 @@ Make type partial - Make type partial + Сделать тип частичным @@ -74,7 +74,7 @@ Suppress or configure issues - Suppress or configure issues + Подавление проблем или настройка уровня их серьезности diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.tr.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.tr.xlf index 45a63b7e593cb..75f2c8c284b0b 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.tr.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.tr.xlf @@ -44,7 +44,7 @@ Fix name violation: {0} - Fix name violation: {0} + Ad ihlalini düzelt: {0} @@ -59,7 +59,7 @@ Make type partial - Make type partial + Türü kısmi hale getir @@ -74,7 +74,7 @@ Suppress or configure issues - Suppress or configure issues + Sorunları gizle veya yapılandır diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.zh-Hans.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.zh-Hans.xlf index 0fa090a5fa3d0..8ef2baf122a89 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.zh-Hans.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.zh-Hans.xlf @@ -44,7 +44,7 @@ Fix name violation: {0} - Fix name violation: {0} + 解决名称冲突: {0} @@ -59,7 +59,7 @@ Make type partial - Make type partial + 将类型设置为部分 @@ -74,7 +74,7 @@ Suppress or configure issues - Suppress or configure issues + 抑制或配置方面的问题 diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.zh-Hant.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.zh-Hant.xlf index 88d03df6b3341..634fa0e4432f2 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.zh-Hant.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.zh-Hant.xlf @@ -44,7 +44,7 @@ Fix name violation: {0} - Fix name violation: {0} + 修正名稱違規: {0} @@ -59,7 +59,7 @@ Make type partial - Make type partial + 將類型設定為部份 @@ -74,7 +74,7 @@ Suppress or configure issues - Suppress or configure issues + 抑制或設定問題 diff --git a/src/Analyzers/VisualBasic/Analyzers/CodeStyle/VisualBasicAnalyzerOptionsProvider.vb b/src/Analyzers/VisualBasic/Analyzers/CodeStyle/VisualBasicAnalyzerOptionsProvider.vb index f65569559fddf..769219a959984 100644 --- a/src/Analyzers/VisualBasic/Analyzers/CodeStyle/VisualBasicAnalyzerOptionsProvider.vb +++ b/src/Analyzers/VisualBasic/Analyzers/CodeStyle/VisualBasicAnalyzerOptionsProvider.vb @@ -16,19 +16,19 @@ Namespace Microsoft.CodeAnalysis.Diagnostics ''' ''' Document editorconfig options. ''' - Private ReadOnly _options As AnalyzerConfigOptions + Private ReadOnly _options As IOptionsReader ''' ''' Fallback options - the default options in Code Style layer. ''' Private ReadOnly _fallbackOptions As IdeAnalyzerOptions - Public Sub New(options As AnalyzerConfigOptions, fallbackOptions As IdeAnalyzerOptions) + Public Sub New(options As IOptionsReader, fallbackOptions As IdeAnalyzerOptions) _options = options _fallbackOptions = fallbackOptions End Sub - Public Sub New(options As AnalyzerConfigOptions, fallbackOptions As AnalyzerOptions) + Public Sub New(options As IOptionsReader, fallbackOptions As AnalyzerOptions) MyClass.New(options, fallbackOptions.GetIdeOptions()) End Sub @@ -67,7 +67,7 @@ Namespace Microsoft.CodeAnalysis.Diagnostics End Property Private Function GetOption(Of TValue)([option] As Option2(Of CodeStyleOption2(Of TValue)), defaultValue As CodeStyleOption2(Of TValue)) As CodeStyleOption2(Of TValue) - Return _options.GetEditorConfigOption([option], defaultValue) + Return _options.GetOption([option], defaultValue) End Function Private ReadOnly Property FallbackSimplifierOptions As VisualBasicSimplifierOptions @@ -87,34 +87,39 @@ Namespace Microsoft.CodeAnalysis.Diagnostics End Operator Public Shared Widening Operator CType(provider As VisualBasicAnalyzerOptionsProvider) As AnalyzerOptionsProvider - Return New AnalyzerOptionsProvider(provider._options, provider._fallbackOptions) + Return New AnalyzerOptionsProvider(provider._options, LanguageNames.VisualBasic, provider._fallbackOptions) End Operator End Structure Friend Module VisualBasicAnalyzerOptionsProviders + + Public Function GetVisualBasicAnalyzerOptions(options As AnalyzerOptions, syntaxTree As SyntaxTree) As VisualBasicAnalyzerOptionsProvider + Return New VisualBasicAnalyzerOptionsProvider(options.AnalyzerConfigOptionsProvider.GetOptions(syntaxTree).GetOptionsReader(), options) + End Function + Public Function GetVisualBasicAnalyzerOptions(context As SemanticModelAnalysisContext) As VisualBasicAnalyzerOptionsProvider - Return New VisualBasicAnalyzerOptionsProvider(context.Options.AnalyzerConfigOptionsProvider.GetOptions(context.SemanticModel.SyntaxTree), context.Options) + Return GetVisualBasicAnalyzerOptions(context.Options, context.SemanticModel.SyntaxTree) End Function Public Function GetVisualBasicAnalyzerOptions(context As SyntaxNodeAnalysisContext) As VisualBasicAnalyzerOptionsProvider - Return New VisualBasicAnalyzerOptionsProvider(context.Options.AnalyzerConfigOptionsProvider.GetOptions(context.Node.SyntaxTree), context.Options) + Return GetVisualBasicAnalyzerOptions(context.Options, context.Node.SyntaxTree) End Function Public Function GetVisualBasicAnalyzerOptions(context As SyntaxTreeAnalysisContext) As VisualBasicAnalyzerOptionsProvider - Return New VisualBasicAnalyzerOptionsProvider(context.Options.AnalyzerConfigOptionsProvider.GetOptions(context.Tree), context.Options) + Return GetVisualBasicAnalyzerOptions(context.Options, context.Tree) End Function Public Function GetVisualBasicAnalyzerOptions(context As OperationAnalysisContext) As VisualBasicAnalyzerOptionsProvider - Return New VisualBasicAnalyzerOptionsProvider(context.Options.AnalyzerConfigOptionsProvider.GetOptions(context.Operation.Syntax.SyntaxTree), context.Options) + Return GetVisualBasicAnalyzerOptions(context.Options, context.Operation.Syntax.SyntaxTree) End Function Public Function GetVisualBasicAnalyzerOptions(context As CodeBlockAnalysisContext) As VisualBasicAnalyzerOptionsProvider - Return New VisualBasicAnalyzerOptionsProvider(context.Options.AnalyzerConfigOptionsProvider.GetOptions(context.SemanticModel.SyntaxTree), context.Options) + Return GetVisualBasicAnalyzerOptions(context.Options, context.SemanticModel.SyntaxTree) End Function End Module End Namespace diff --git a/src/Analyzers/VisualBasic/CodeFixes/UseNullPropagation/VisualBasicUseNullPropagationCodeFixProvider.vb b/src/Analyzers/VisualBasic/CodeFixes/UseNullPropagation/VisualBasicUseNullPropagationCodeFixProvider.vb index 6e3a31f9aa536..d2844caf72300 100644 --- a/src/Analyzers/VisualBasic/CodeFixes/UseNullPropagation/VisualBasicUseNullPropagationCodeFixProvider.vb +++ b/src/Analyzers/VisualBasic/CodeFixes/UseNullPropagation/VisualBasicUseNullPropagationCodeFixProvider.vb @@ -31,6 +31,18 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UseNullPropagation Public Sub New() End Sub + Protected Overrides Function TryGetBlock(node As SyntaxNode, ByRef block As ExecutableStatementSyntax) As Boolean + Return False + End Function + + Protected Overrides Function ReplaceBlockStatements(block As ExecutableStatementSyntax, newInnerStatement As ExecutableStatementSyntax) As ExecutableStatementSyntax + Throw ExceptionUtilities.Unreachable() + End Function + + Protected Overrides Function PostProcessElseIf(ifStatement As MultiLineIfBlockSyntax, newWhenTrueStatement As ExecutableStatementSyntax) As SyntaxNode + Throw ExceptionUtilities.Unreachable() + End Function + Protected Overrides Function ElementBindingExpression(argumentList As ArgumentListSyntax) As InvocationExpressionSyntax Return SyntaxFactory.InvocationExpression(Nothing, argumentList) End Function diff --git a/src/Analyzers/VisualBasic/Tests/AddRequiredParentheses/AddRequiredParenthesesTests.vb b/src/Analyzers/VisualBasic/Tests/AddRequiredParentheses/AddRequiredParenthesesTests.vb index 05c6226c0906e..4f1189e9fc8b3 100644 --- a/src/Analyzers/VisualBasic/Tests/AddRequiredParentheses/AddRequiredParenthesesTests.vb +++ b/src/Analyzers/VisualBasic/Tests/AddRequiredParentheses/AddRequiredParenthesesTests.vb @@ -8,163 +8,205 @@ Imports Microsoft.CodeAnalysis.Diagnostics Imports Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics Imports Microsoft.CodeAnalysis.VisualBasic.AddRequiredParentheses +Imports VerifyVB = Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions.VisualBasicCodeFixVerifier(Of Microsoft.CodeAnalysis.VisualBasic.AddRequiredParentheses.VisualBasicAddRequiredParenthesesForBinaryLikeExpressionDiagnosticAnalyzer, Microsoft.CodeAnalysis.AddRequiredParentheses.AddRequiredParenthesesCodeFixProvider) + Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.AddRequiredParentheses Partial Public Class AddRequiredParenthesesTests - Inherits AbstractVisualBasicDiagnosticProviderBasedUserDiagnosticTest + Private Const RequireAllParenthesesForClarity As String = "[*] +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity +dotnet_style_parentheses_in_other_operators = never_if_unnecessary +" + Private Const RequireOtherBinaryParenthesesForClarity As String = "[*] +dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary +dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity +dotnet_style_parentheses_in_other_operators = never_if_unnecessary +" + Private Const RequireArithmeticBinaryParenthesesForClarity As String = "[*] +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity +dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary +dotnet_style_parentheses_in_other_binary_operators = never_if_unnecessary +dotnet_style_parentheses_in_other_operators = never_if_unnecessary +" + Private Shared Async Function VerifyCodeFixAsync(code As String, fixedCode As String, editorConfig As String) As Task + Await New VerifyVB.Test With + { + .TestCode = code, + .FixedCode = fixedCode, + .EditorConfig = editorConfig + }.RunAsync() + End Function - Friend Overrides Function CreateDiagnosticProviderAndFixer(Workspace As Workspace) As (DiagnosticAnalyzer, CodeFixProvider) - Return (New VisualBasicAddRequiredParenthesesForBinaryLikeExpressionDiagnosticAnalyzer(), New AddRequiredParenthesesCodeFixProvider()) + Private Shared Async Function VerifyNoCodeFixAsync(code As String, editorConfig As String) As Task + Await New VerifyVB.Test With + { + .TestCode = code, + .FixedCode = code, + .EditorConfig = editorConfig + }.RunAsync() End Function Public Async Function TestArithmeticPrecedence() As Task - Await TestInRegularAndScript1Async( + Await VerifyCodeFixAsync( "class C sub M() - dim x = 1 + 2 $$* 3 + dim x = 1 + 2 [|*|] 3 end sub end class", "class C sub M() dim x = 1 + (2 * 3) end sub -end class", parameters:=New TestParameters(options:=RequireAllParenthesesForClarity)) +end class", RequireAllParenthesesForClarity) End Function Public Async Function TestNoArithmeticOnLowerPrecedence() As Task - Await TestMissingAsync( + Await VerifyCodeFixAsync( "class C sub M() - dim x = 1 $$+ 2 * 3 + dim x = 1 + 2 [|*|] 3 end sub -end class", parameters:=New TestParameters(options:=RequireAllParenthesesForClarity)) +end class", +"class C + sub M() + dim x = 1 + (2 * 3) + end sub +end class", RequireAllParenthesesForClarity) End Function Public Async Function TestNotIfArithmeticPrecedenceStaysTheSame() As Task - Await TestMissingAsync( + Await VerifyNoCodeFixAsync( "class C sub M() - dim x = 1 + 2 $$+ 3 + dim x = 1 + 2 + 3 end sub -end class", parameters:=New TestParameters(options:=RequireAllParenthesesForClarity)) +end class", RequireAllParenthesesForClarity) End Function Public Async Function TestNotIfArithmeticPrecedenceIsNotEnforced1() As Task - Await TestMissingAsync( + Await VerifyNoCodeFixAsync( "class C sub M() - dim x = 1 + 2 $$+ 3 + dim x = 1 + 2 + 3 end sub -end class", parameters:=New TestParameters(options:=RequireOtherBinaryParenthesesForClarity)) +end class", RequireOtherBinaryParenthesesForClarity) End Function Public Async Function TestNotIfArithmeticPrecedenceIsNotEnforced2() As Task - Await TestMissingAsync( + Await VerifyNoCodeFixAsync( "class C sub M() - dim x = 1 + 2 $$* 3 + dim x = 1 + 2 * 3 end sub -end class", parameters:=New TestParameters(options:=RequireOtherBinaryParenthesesForClarity)) +end class", RequireOtherBinaryParenthesesForClarity) End Function Public Async Function TestLogicalPrecedence() As Task - Await TestInRegularAndScript1Async( + Await VerifyCodeFixAsync( "class C sub M() - dim x = a orelse b $$andalso c + dim x = {|BC30451:a|} orelse {|BC30451:b|} [|andalso|] {|BC30109:c|} end sub end class", "class C sub M() - dim x = a orelse (b andalso c) + dim x = {|BC30451:a|} orelse ({|BC30451:b|} andalso {|BC30109:c|}) end sub -end class", parameters:=New TestParameters(options:=RequireAllParenthesesForClarity)) +end class", RequireAllParenthesesForClarity) End Function Public Async Function TestNoLogicalOnLowerPrecedence() As Task - Await TestMissingAsync( + Await VerifyCodeFixAsync( +"class C + sub M() + dim x = {|BC30451:a|} orelse {|BC30451:b|} [|andalso|] {|BC30109:c|} + end sub +end class", "class C sub M() - dim x = a $$orelse b andalso c + dim x = {|BC30451:a|} orelse ({|BC30451:b|} andalso {|BC30109:c|}) end sub -end class", parameters:=New TestParameters(options:=RequireAllParenthesesForClarity)) +end class", RequireAllParenthesesForClarity) End Function Public Async Function TestNotIfLogicalPrecedenceStaysTheSame() As Task - Await TestMissingAsync( + Await VerifyNoCodeFixAsync( "class C sub M() - int x = a orelse b $$orelse c + {|BC30451:int|} {|BC30800:{|BC30451:x|} = {|BC30451:a|} orelse {|BC30451:b|} orelse {|BC30109:c|}|} end sub -end class", parameters:=New TestParameters(options:=RequireAllParenthesesForClarity)) +end class", RequireAllParenthesesForClarity) End Function Public Async Function TestNotIfLogicalPrecedenceIsNotEnforced() As Task - Await TestMissingAsync( + Await VerifyNoCodeFixAsync( "class C sub M() - dim x = a orelse b $$orelse c + dim x = {|BC30451:a|} orelse {|BC30451:b|} orelse {|BC30109:c|} end sub -end class", parameters:=New TestParameters(options:=RequireArithmeticBinaryParenthesesForClarity)) +end class", RequireArithmeticBinaryParenthesesForClarity) End Function Public Async Function TestMixedArithmeticAndLogical() As Task - Await TestMissingAsync( + Await VerifyNoCodeFixAsync( "class C sub M() - dim x = a = b $$andalso c = d + dim x = {|BC30451:a|} = {|BC30451:b|} andalso {|BC30109:c|} = {|BC30451:d|} end sub -end class", New TestParameters(options:=RequireAllParenthesesForClarity)) +end class", RequireAllParenthesesForClarity) End Function Public Async Function TestShiftPrecedence1() As Task - Await TestInRegularAndScript1Async( + Await VerifyCodeFixAsync( "class C sub M() - dim x = 1 $$+ 2 << 3 + dim x = 1 [|+|] 2 << 3 end sub end class", "class C sub M() dim x = (1 + 2) << 3 end sub -end class", parameters:=New TestParameters(options:=RequireAllParenthesesForClarity)) +end class", RequireAllParenthesesForClarity) End Function Public Async Function TestShiftPrecedence2() As Task - Await TestInRegularAndScript1Async( + Await VerifyCodeFixAsync( "class C sub M() - dim x = 1 $$+ 2 << 3 + dim x = 1 [|+|] 2 << 3 end sub end class", "class C sub M() dim x = (1 + 2) << 3 end sub -end class", parameters:=New TestParameters(options:=RequireArithmeticBinaryParenthesesForClarity)) +end class", RequireArithmeticBinaryParenthesesForClarity) End Function Public Async Function TestShiftPrecedence3() As Task - Await TestMissingAsync( + Await VerifyNoCodeFixAsync( "class C sub M() - dim x = 1 $$<< 2 << 3 + dim x = 1 << 2 << 3 end sub -end class", parameters:=New TestParameters(options:=RequireArithmeticBinaryParenthesesForClarity)) +end class", RequireArithmeticBinaryParenthesesForClarity) End Function End Class End Namespace diff --git a/src/Analyzers/VisualBasic/Tests/Iterator/IteratorTests.vb b/src/Analyzers/VisualBasic/Tests/Iterator/IteratorTests.vb index e22ed662f167e..9d2552ac7532c 100644 --- a/src/Analyzers/VisualBasic/Tests/Iterator/IteratorTests.vb +++ b/src/Analyzers/VisualBasic/Tests/Iterator/IteratorTests.vb @@ -5,26 +5,41 @@ Imports Microsoft.CodeAnalysis.CodeFixes Imports Microsoft.CodeAnalysis.Diagnostics Imports Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics +Imports Microsoft.CodeAnalysis.Testing Imports Microsoft.CodeAnalysis.VisualBasic.CodeFixes.Iterator +Imports VerifyConvertToIterator = Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions.VisualBasicCodeFixVerifier(Of Microsoft.CodeAnalysis.Testing.EmptyDiagnosticAnalyzer, Microsoft.CodeAnalysis.VisualBasic.CodeFixes.Iterator.VisualBasicConvertToIteratorCodeFixProvider) +Imports VerifyConvertToYield = Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions.VisualBasicCodeFixVerifier(Of Microsoft.CodeAnalysis.Testing.EmptyDiagnosticAnalyzer, Microsoft.CodeAnalysis.VisualBasic.CodeFixes.Iterator.VisualBasicChangeToYieldCodeFixProvider) + Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CodeRefactorings.Iterator Public Class ConvertToIteratorTests - Inherits AbstractVisualBasicDiagnosticProviderBasedUserDiagnosticTest + Private Shared Async Function VerifyCodeFixAsync(code As String, fixedCode As String) As Task + Await New VerifyConvertToIterator.Test With + { + .TestCode = code, + .FixedCode = fixedCode, + .CodeActionValidationMode = CodeActionValidationMode.None + }.RunAsync() + End Function - Friend Overrides Function CreateDiagnosticProviderAndFixer(workspace As Workspace) As (DiagnosticAnalyzer, CodeFixProvider) - Return (Nothing, New VisualBasicConvertToIteratorCodeFixProvider()) + Private Shared Async Function VerifyNoCodeFixAsync(code As String) As Task + Await New VerifyConvertToIterator.Test With + { + .TestCode = code, + .FixedCode = code + }.RunAsync() End Function Public Async Function TestConvertToIteratorFunction() As Task - Await TestInRegularAndScriptAsync( + Await VerifyCodeFixAsync( "Imports System Imports System.Collections.Generic Module Module1 Function M() As IEnumerable(Of Integer) - [|Yield|] 1 + {|BC30451:Yield|} {|BC30800:1 |} End Function End Module", "Imports System @@ -39,24 +54,24 @@ End Module") Public Async Function TestConvertToIteratorSub() As Task - Await TestMissingInRegularAndScriptAsync( + Await VerifyNoCodeFixAsync( "Module Module1 - Sub M() As - [|Yield|] 1 + Sub M() {|BC30205:As|} + {|BC30451:Yield|} {|BC30800:1 |} End Sub End Module") End Function Public Async Function TestConvertToIteratorFunctionLambda() As Task - Await TestInRegularAndScriptAsync( + Await VerifyCodeFixAsync( "Imports System Imports System.Collections.Generic Module Module1 Sub M() Dim a As Func(Of IEnumerable(Of Integer)) = Function() - [|Yield|] 0 + {|BC30451:Yield|} {|BC30800:0 |} End Function End Sub End Module", @@ -74,14 +89,14 @@ End Module") Public Async Function TestConvertToIteratorSubLambda() As Task - Await TestMissingInRegularAndScriptAsync( + Await VerifyNoCodeFixAsync( "Imports System Imports System.Collections.Generic Module Module1 Sub M() Dim a As Func(Of IEnumerable(Of Integer)) = Sub() - [|Yield|] 0 + {|BC30451:Yield|} {|BC30800:1 |} End Sub End Sub End Module") @@ -89,26 +104,26 @@ End Module") Public Async Function TestConvertToIteratorSingleLineFunctionLambda() As Task - Await TestMissingInRegularAndScriptAsync( + Await VerifyNoCodeFixAsync( "Imports System Imports System.Collections.Generic Module Module1 Sub M() - Dim a As Func(Of IEnumerable(Of Integer)) = Function() [|Yield|] 0 + Dim a As Func(Of IEnumerable(Of Integer)) = Function() {|BC30451:Yield|} {|BC30205:1|} End Sub End Module") End Function Public Async Function TestConvertToIteratorSingleLineSubLambda() As Task - Await TestMissingInRegularAndScriptAsync( + Await VerifyNoCodeFixAsync( "Imports System Imports System.Collections.Generic Module Module1 Sub M() - Dim a As Func(Of IEnumerable(Of Integer)) = Sub() [|Yield|] 0 + Dim a As Func(Of IEnumerable(Of Integer)) = Sub() {|BC30451:Yield|} {|BC30800:1 |} End Sub End Module") End Function @@ -116,22 +131,32 @@ End Module") Public Class ChangeToYieldTests - Inherits AbstractVisualBasicDiagnosticProviderBasedUserDiagnosticTest + Private Shared Async Function VerifyCodeFixAsync(code As String, fixedCode As String) As Task + Await New VerifyConvertToYield.Test With + { + .TestCode = code, + .FixedCode = fixedCode + }.RunAsync() + End Function - Friend Overrides Function CreateDiagnosticProviderAndFixer(workspace As Workspace) As (DiagnosticAnalyzer, CodeFixProvider) - Return (Nothing, New VisualBasicChangeToYieldCodeFixProvider()) + Private Shared Async Function VerifyNoCodeFixAsync(code As String) As Task + Await New VerifyConvertToYield.Test With + { + .TestCode = code, + .FixedCode = code + }.RunAsync() End Function Public Async Function TestChangeToYieldCodeFixProviderFunction() As Task - Await TestInRegularAndScriptAsync( + Await VerifyCodeFixAsync( "Module Module1 - Iterator Function M() As IEnumerable(Of Integer) - [|Return|] 1 + Iterator Function M() As {|BC30002:IEnumerable(Of Integer)|} + {|BC36942:Return 1|} End Function End Module", "Module Module1 - Iterator Function M() As IEnumerable(Of Integer) + Iterator Function M() As {|BC30002:IEnumerable(Of Integer)|} Yield 1 End Function End Module") @@ -139,14 +164,14 @@ End Module") Public Async Function TestChangeToYieldCodeFixProviderSub() As Task - Await TestInRegularAndScriptAsync( + Await VerifyCodeFixAsync( "Module Module1 - Iterator Sub M() - [|Return|] 1 + Iterator {|BC36938:Sub|} M() + {|BC36942:Return 1|} End Sub End Module", "Module Module1 - Iterator Sub M() + Iterator {|BC36938:Sub|} M() Yield 1 End Sub End Module") @@ -154,11 +179,11 @@ End Module") Public Async Function TestChangeToYieldCodeFixProviderFunctionLambda() As Task - Await TestInRegularAndScriptAsync( + Await VerifyCodeFixAsync( "Module Module1 Sub M() Dim a = Iterator Function() - [|Return|] 0 + {|BC36942:Return 0|} End Function End Sub End Module", @@ -173,17 +198,17 @@ End Module") Public Async Function TestChangeToYieldCodeFixProviderSubLambda() As Task - Await TestInRegularAndScriptAsync( + Await VerifyCodeFixAsync( "Module Module1 Sub M() - Dim a = Iterator Sub() - [|Return|] 0 + Dim a = Iterator {|BC36938:Sub|}() + {|BC36942:Return 0|} End Sub End Sub End Module", "Module Module1 Sub M() - Dim a = Iterator Sub() + Dim a = Iterator {|BC36938:Sub|}() Yield 0 End Sub End Sub @@ -192,24 +217,24 @@ End Module") Public Async Function TestChangeToYieldCodeFixProviderSingleLineFunctionLambda() As Task - Await TestMissingInRegularAndScriptAsync("Module Module1 + Await VerifyNoCodeFixAsync("Module Module1 Sub M() - Dim a = Iterator Function() [|Return|] 0 + Dim a = {|BC36947:Iterator Function() |}{|BC30201:|}Return 0 End Sub End Module") End Function Public Async Function TestChangeToYieldCodeFixProviderSingleLineSubLambda() As Task - Await TestInRegularAndScriptAsync( + Await VerifyCodeFixAsync( "Module Module1 Sub M() - Dim a = Iterator Sub() [|Return|] 0 + Dim a = Iterator {|BC36938:Sub|}() {|BC36942:Return 0|} End Sub End Module", "Module Module1 Sub M() - Dim a = Iterator Sub() Yield 0 + Dim a = Iterator {|BC36938:Sub|}() Yield 0 End Sub End Module") End Function diff --git a/src/Analyzers/VisualBasic/Tests/UseNullPropagation/UseNullPropagationTests.vb b/src/Analyzers/VisualBasic/Tests/UseNullPropagation/UseNullPropagationTests.vb index bfd122f941919..571cc33315de5 100644 --- a/src/Analyzers/VisualBasic/Tests/UseNullPropagation/UseNullPropagationTests.vb +++ b/src/Analyzers/VisualBasic/Tests/UseNullPropagation/UseNullPropagationTests.vb @@ -131,6 +131,21 @@ Class C End Class") End Function + + Public Async Function TestIfStatement_NotIfTrue() As Task + Await TestMissingInRegularAndScriptAsync( +" +Imports System + +Class C + Sub M(o As Object) + [||]If True + o.ToString() + End If + End Sub +End Class") + End Function + Public Async Function TestIfStatement_NotWithElse() As Task Await TestMissingInRegularAndScriptAsync( @@ -163,6 +178,24 @@ Class C End Class") End Function + + Public Async Function TestIfStatement_NotIfTrueInsideElse() As Task + Await TestMissingInRegularAndScriptAsync( +" +Imports System + +Class C + Sub M(o As Object) + If True + Else + [||]If True + o.ToString() + End If + End If + End Sub +End Class") + End Function + Public Async Function TestIfStatement_NotWithMultipleStatements() As Task Await TestMissingInRegularAndScriptAsync( @@ -1104,5 +1137,20 @@ public class C end sub end class") End Function + + + Public Async Function TestElseIf() As Task + ' Subject to improve + Await TestMissingInRegularAndScriptAsync( +" +Class C + Sub M(s as String) + If True Then + ElseIf s [||]IsNot Nothing + s.ToString() + End If + End Sub +End Class") + End Function End Class End Namespace diff --git a/src/Compilers/CSharp/Portable/Binder/Binder.QueryUnboundLambdaState.cs b/src/Compilers/CSharp/Portable/Binder/Binder.QueryUnboundLambdaState.cs index 0a312e8c38472..96009e7e44ace 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder.QueryUnboundLambdaState.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder.QueryUnboundLambdaState.cs @@ -48,7 +48,7 @@ public override bool HasExplicitReturnType(out RefKind refKind, out TypeWithAnno public override bool IsStatic => false; public override bool HasParamsArray => false; public override RefKind RefKind(int index) { return Microsoft.CodeAnalysis.RefKind.None; } - public override DeclarationScope DeclaredScope(int index) => DeclarationScope.Unscoped; + public override ScopedKind DeclaredScope(int index) => ScopedKind.None; public override MessageID MessageID { get { return MessageID.IDS_FeatureQueryExpression; } } // TODO: what is the correct ID here? public override Location ParameterLocation(int index) { return _parameters[index].Locations[0]; } // Query unbound lambdas don't have associated parameter syntax diff --git a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs index 6ebc085102644..93fd2aac31472 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs @@ -11,17 +11,14 @@ using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.CodeGen; using Microsoft.CodeAnalysis.CSharp.Symbols; -using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.PooledObjects; -using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp { - internal partial class Binder - { #nullable enable - + internal partial class RefSafetyAnalysis + { private enum EscapeLevel : uint { CallingMethod = Binder.CallingMethodScope, @@ -156,9 +153,11 @@ public void Deconstruct(out ParameterSymbol? parameter, out BoundExpression argu ? p.ToString() : Argument.ToString(); } - + } #nullable disable + internal partial class Binder + { /// /// For the purpose of escape verification we operate with the depth of local scopes. /// The depth is a uint, with smaller number representing shallower/wider scopes. @@ -554,7 +553,7 @@ internal bool CheckValueKind(SyntaxNode node, BoundExpression expr, BindValueKin // constants/literals are strictly RValues // void is not even an RValue - if ((expr.ConstantValue != null) || (expr.Type.GetSpecialTypeSafe() == SpecialType.System_Void)) + if ((expr.ConstantValueOpt != null) || (expr.Type.GetSpecialTypeSafe() == SpecialType.System_Void)) { Error(diagnostics, GetStandardLvalueError(valueKind), node); return false; @@ -850,19 +849,22 @@ private bool CheckLocalValueKind(SyntaxNode node, BoundLocal local, BindValueKin return true; } + } + internal partial class RefSafetyAnalysis + { private bool CheckLocalRefEscape(SyntaxNode node, BoundLocal local, uint escapeTo, bool checkingReceiver, BindingDiagnosticBag diagnostics) { LocalSymbol localSymbol = local.LocalSymbol; // if local symbol can escape to the same or wider/shallower scope then escapeTo // then it is all ok, otherwise it is an error. - if (localSymbol.RefEscapeScope <= escapeTo) + if (GetLocalScopes(localSymbol).RefEscapeScope <= escapeTo) { return true; } - var inUnsafeRegion = this.InUnsafeRegion; + var inUnsafeRegion = _inUnsafeRegion; if (escapeTo is Binder.CallingMethodScope or Binder.ReturnOnlyScope) { if (localSymbol.RefKind == RefKind.None) @@ -892,7 +894,10 @@ private bool CheckLocalRefEscape(SyntaxNode node, BoundLocal local, uint escapeT Error(diagnostics, inUnsafeRegion ? ErrorCode.WRN_EscapeVariable : ErrorCode.ERR_EscapeVariable, node, localSymbol); return inUnsafeRegion; } + } + internal partial class Binder + { private bool CheckParameterValueKind(SyntaxNode node, BoundParameter parameter, BindValueKind valueKind, bool checkingReceiver, BindingDiagnosticBag diagnostics) { ParameterSymbol parameterSymbol = parameter.ParameterSymbol; @@ -921,7 +926,10 @@ private bool CheckParameterValueKind(SyntaxNode node, BoundParameter parameter, return true; } + } + internal partial class RefSafetyAnalysis + { private static EscapeLevel? EscapeLevelFromScope(uint scope) => scope switch { Binder.ReturnOnlyScope => EscapeLevel.ReturnOnly, @@ -933,7 +941,7 @@ private static uint GetParameterValEscape(ParameterSymbol parameter) { return parameter switch { - { EffectiveScope: DeclarationScope.ValueScoped } => Binder.CurrentMethodScope, + { EffectiveScope: ScopedKind.ScopedValue } => Binder.CurrentMethodScope, { RefKind: RefKind.Out, UseUpdatedEscapeRules: true } => Binder.ReturnOnlyScope, _ => Binder.CallingMethodScope }; @@ -947,7 +955,7 @@ private static uint GetParameterRefEscape(ParameterSymbol parameter) return parameter switch { { RefKind: RefKind.None } => Binder.CurrentMethodScope, - { EffectiveScope: DeclarationScope.RefScoped } => Binder.CurrentMethodScope, + { EffectiveScope: ScopedKind.ScopedRef } => Binder.CurrentMethodScope, { HasUnscopedRefAttribute: true, RefKind: RefKind.Out } => Binder.ReturnOnlyScope, { HasUnscopedRefAttribute: true, IsThis: false } => Binder.CallingMethodScope, _ => Binder.ReturnOnlyScope @@ -960,12 +968,12 @@ private static uint GetParameterRefEscape(ParameterSymbol parameter) private bool CheckParameterValEscape(SyntaxNode node, ParameterSymbol parameter, uint escapeTo, BindingDiagnosticBag diagnostics) { Debug.Assert(escapeTo is Binder.CallingMethodScope or Binder.ReturnOnlyScope); - if (UseUpdatedEscapeRules) + if (_useUpdatedEscapeRules) { if (GetParameterValEscape(parameter) > escapeTo) { - Error(diagnostics, this.InUnsafeRegion ? ErrorCode.WRN_EscapeVariable : ErrorCode.ERR_EscapeVariable, node, parameter); - return this.InUnsafeRegion; + Error(diagnostics, _inUnsafeRegion ? ErrorCode.WRN_EscapeVariable : ErrorCode.ERR_EscapeVariable, node, parameter); + return _inUnsafeRegion; } return true; } @@ -981,9 +989,9 @@ private bool CheckParameterRefEscape(SyntaxNode node, BoundExpression parameter, var refSafeToEscape = GetParameterRefEscape(parameterSymbol); if (refSafeToEscape > escapeTo) { - var isRefScoped = parameterSymbol.EffectiveScope == DeclarationScope.RefScoped; + var isRefScoped = parameterSymbol.EffectiveScope == ScopedKind.ScopedRef; Debug.Assert(parameterSymbol.RefKind == RefKind.None || isRefScoped || refSafeToEscape == Binder.ReturnOnlyScope); - var inUnsafeRegion = this.InUnsafeRegion; + var inUnsafeRegion = _inUnsafeRegion; if (parameter is BoundThisReference) { @@ -1015,7 +1023,10 @@ private bool CheckParameterRefEscape(SyntaxNode node, BoundExpression parameter, // can ref-escape to any scope otherwise return true; } + } + internal partial class Binder + { private bool CheckFieldValueKind(SyntaxNode node, BoundFieldAccess fieldAccess, BindValueKind valueKind, bool checkingReceiver, BindingDiagnosticBag diagnostics) { var fieldSymbol = fieldAccess.FieldSymbol; @@ -1142,7 +1153,10 @@ private bool CheckSimpleAssignmentValueKind(SyntaxNode node, BoundAssignmentOper Error(diagnostics, GetStandardLvalueError(valueKind), node); return false; } + } + internal partial class RefSafetyAnalysis + { private uint GetFieldRefEscape(BoundFieldAccess fieldAccess, uint scopeOfTheContainingExpression) { var fieldSymbol = fieldAccess.FieldSymbol; @@ -1153,7 +1167,7 @@ private uint GetFieldRefEscape(BoundFieldAccess fieldAccess, uint scopeOfTheCont return Binder.CallingMethodScope; } - if (UseUpdatedEscapeRules) + if (_useUpdatedEscapeRules) { // SPEC: If `F` is a `ref` field its ref-safe-to-escape scope is the safe-to-escape scope of `e`. if (fieldSymbol.RefKind != RefKind.None) @@ -1177,7 +1191,7 @@ private bool CheckFieldRefEscape(SyntaxNode node, BoundFieldAccess fieldAccess, Debug.Assert(fieldAccess.ReceiverOpt is { }); - if (UseUpdatedEscapeRules) + if (_useUpdatedEscapeRules) { // SPEC: If `F` is a `ref` field its ref-safe-to-escape scope is the safe-to-escape scope of `e`. if (fieldSymbol.RefKind != RefKind.None) @@ -1203,7 +1217,10 @@ private bool CheckFieldLikeEventRefEscape(SyntaxNode node, BoundEventAccess even // for other events defer to the receiver. return CheckRefEscape(node, eventAccess.ReceiverOpt, escapeFrom, escapeTo, checkingReceiver: true, diagnostics: diagnostics); } + } + internal partial class Binder + { private bool CheckEventValueKind(BoundEventAccess boundEvent, BindValueKind valueKind, BindingDiagnosticBag diagnostics) { // Compound assignment (actually "event assignment") is allowed "everywhere", subject to the restrictions of @@ -1581,7 +1598,10 @@ private bool IsBadBaseAccess(SyntaxNode node, BoundExpression receiverOpt, Symbo return false; } + } + internal partial class RefSafetyAnalysis + { internal uint GetInterpolatedStringHandlerConversionEscapeScope( BoundExpression expression, uint scopeOfTheContainingExpression) @@ -1729,18 +1749,27 @@ private uint GetInvocationEscapeWithUpdatedRules( isRefEscape, ignoreArglistRefKinds: true, // https://github.com/dotnet/roslyn/issues/63325: for compatibility with C#10 implementation. argsAndParamsAll); - foreach (var argAndParam in argsAndParamsAll) - { - var argument = argAndParam.Argument; - uint argEscape = argAndParam.IsRefEscape ? - GetRefEscape(argument, scopeOfTheContainingExpression) : - GetValEscape(argument, scopeOfTheContainingExpression); - escapeScope = Math.Max(escapeScope, argEscape); - if (escapeScope >= scopeOfTheContainingExpression) + var returnsRefToRefStruct = ReturnsRefToRefStruct(symbol); + foreach (var (param, argument, _, isArgumentRefEscape) in argsAndParamsAll) + { + // SPEC: + // If `M()` does return ref-to-ref-struct, the *safe-to-escape* is the same as the *safe-to-escape* of all arguments which are ref-to-ref-struct. It is an error if there are multiple arguments with different *safe-to-escape* because of *method arguments must match*. + // If `M()` does return ref-to-ref-struct, the *ref-safe-to-escape* is the narrowest *ref-safe-to-escape* contributed by all arguments which are ref-to-ref-struct. + // + if (!returnsRefToRefStruct + || (param is null or { RefKind: not RefKind.None, Type.IsRefLikeType: true } && isArgumentRefEscape == isRefEscape)) { - // can't get any worse - break; + uint argEscape = isArgumentRefEscape ? + GetRefEscape(argument, scopeOfTheContainingExpression) : + GetValEscape(argument, scopeOfTheContainingExpression); + + escapeScope = Math.Max(escapeScope, argEscape); + if (escapeScope >= scopeOfTheContainingExpression) + { + // can't get any worse + break; + } } } argsAndParamsAll.Free(); @@ -1748,6 +1777,19 @@ private uint GetInvocationEscapeWithUpdatedRules( return escapeScope; } + private static bool ReturnsRefToRefStruct(Symbol symbol) + { + var method = symbol switch + { + MethodSymbol m => m, + // We are only getting the method in order to handle a special condition where the method returns by-ref. + // It is an error for a property to have a setter and return by-ref, so we only bother looking for a getter here. + PropertySymbol p => p.GetMethod, + _ => null + }; + return method is { RefKind: not RefKind.None, ReturnType.IsRefLikeType: true }; + } + /// /// Validates whether given invocation can allow its results to escape from level to level. /// The result indicates whether the escape is possible. @@ -1869,24 +1911,33 @@ private bool CheckInvocationEscapeWithUpdatedRules( isRefEscape, ignoreArglistRefKinds: true, // https://github.com/dotnet/roslyn/issues/63325: for compatibility with C#10 implementation. argsAndParamsAll); - foreach (var argAndParam in argsAndParamsAll) - { - var argument = argAndParam.Argument; - bool valid = argAndParam.IsRefEscape ? - CheckRefEscape(argument.Syntax, argument, escapeFrom, escapeTo, false, diagnostics) : - CheckValEscape(argument.Syntax, argument, escapeFrom, escapeTo, false, diagnostics); - if (!valid) + var returnsRefToRefStruct = ReturnsRefToRefStruct(symbol); + foreach (var (param, argument, _, isArgumentRefEscape) in argsAndParamsAll) + { + // SPEC: + // If `M()` does return ref-to-ref-struct, the *safe-to-escape* is the same as the *safe-to-escape* of all arguments which are ref-to-ref-struct. It is an error if there are multiple arguments with different *safe-to-escape* because of *method arguments must match*. + // If `M()` does return ref-to-ref-struct, the *ref-safe-to-escape* is the narrowest *ref-safe-to-escape* contributed by all arguments which are ref-to-ref-struct. + // + if (!returnsRefToRefStruct + || (param is null or { RefKind: not RefKind.None, Type.IsRefLikeType: true } && isArgumentRefEscape == isRefEscape)) { - // For consistency with C#10 implementation, we don't report an additional error - // for the receiver. (In both implementations, the call to Check*Escape() above - // will have reported a specific escape error for the receiver though.) - if ((object)((argument as BoundCapturedReceiverPlaceholder)?.Receiver ?? argument) != receiver) + bool valid = isArgumentRefEscape ? + CheckRefEscape(argument.Syntax, argument, escapeFrom, escapeTo, false, diagnostics) : + CheckValEscape(argument.Syntax, argument, escapeFrom, escapeTo, false, diagnostics); + + if (!valid) { - ReportInvocationEscapeError(syntax, symbol, argAndParam.Parameter, checkingReceiver, diagnostics); + // For consistency with C#10 implementation, we don't report an additional error + // for the receiver. (In both implementations, the call to Check*Escape() above + // will have reported a specific escape error for the receiver though.) + if ((object)((argument as BoundCapturedReceiverPlaceholder)?.Receiver ?? argument) != receiver) + { + ReportInvocationEscapeError(syntax, symbol, param, checkingReceiver, diagnostics); + } + result = false; + break; } - result = false; - break; } } argsAndParamsAll.Free(); @@ -1921,18 +1972,18 @@ private void GetInvocationArgumentsForEscape( _ => throw ExceptionUtilities.UnexpectedValue(symbol) }; - if (receiver is not BoundValuePlaceholderBase && method is not null && receiver.Type!.IsValueType) + if (receiver is not BoundValuePlaceholderBase && method is not null && receiver.Type?.IsValueType == true) { - var receiverAddressKind = method.IsEffectivelyReadOnly ? AddressKind.ReadOnly : AddressKind.Writeable; + var receiverAddressKind = method.IsEffectivelyReadOnly ? Binder.AddressKind.ReadOnly : Binder.AddressKind.Writeable; if (!Binder.HasHome(receiver, receiverAddressKind, - ContainingMemberOrLambda, - Compilation.IsPeVerifyCompatEnabled, + _symbol, + _compilation.IsPeVerifyCompatEnabled, stackLocalsOpt: null)) { // Equivalent to a non-ref local with the underlying receiver as an initializer provided at declaration - receiver = new BoundCapturedReceiverPlaceholder(receiver.Syntax, receiver, LocalScopeDepth, receiver.Type).MakeCompilerGenerated(); + receiver = new BoundCapturedReceiverPlaceholder(receiver.Syntax, receiver, _localScopeDepth, receiver.Type).MakeCompilerGenerated(); } } @@ -1996,8 +2047,18 @@ parameter is not null && parameter.Type.IsRefLikeType && parameter.RefKind.IsWritableReference(); - static bool isMixableArgument(BoundExpression argument) => - argument is not (BoundDeconstructValuePlaceholder { VariableSymbol: not null } or BoundLocal { DeclarationKind: not BoundLocalDeclarationKind.None }); + static bool isMixableArgument(BoundExpression argument) + { + if (argument is BoundDeconstructValuePlaceholder { VariableSymbol: not null } or BoundLocal { DeclarationKind: not BoundLocalDeclarationKind.None }) + { + return false; + } + if (argument.IsDiscardExpression()) + { + return false; + } + return true; + } static EscapeArgument getReceiver(MethodSymbol? method, BoundExpression receiver) { @@ -2220,7 +2281,7 @@ private bool UseUpdatedEscapeRulesForInvocation(Symbol symbol) return method?.UseUpdatedEscapeRules == true; } - private static bool ShouldInferDeclarationExpressionValEscape(BoundExpression argument, [NotNullWhen(true)] out SourceLocalSymbol? localSymbol) + private bool ShouldInferDeclarationExpressionValEscape(BoundExpression argument, [NotNullWhen(true)] out SourceLocalSymbol? localSymbol) { var symbol = argument switch { @@ -2228,7 +2289,8 @@ private static bool ShouldInferDeclarationExpressionValEscape(BoundExpression ar BoundLocal { DeclarationKind: not BoundLocalDeclarationKind.None } l => l.LocalSymbol, _ => null }; - if (symbol is SourceLocalSymbol { ValEscapeScope: CallingMethodScope } local) + if (symbol is SourceLocalSymbol local && + GetLocalScopes(local).ValEscapeScope == Binder.CallingMethodScope) { localSymbol = local; return true; @@ -2308,7 +2370,9 @@ private bool CheckInvocationArgMixing( continue; } - if (refKind.IsWritableReference() && argument.Type?.IsRefLikeType == true) + if (refKind.IsWritableReference() + && !argument.IsDiscardExpression() + && argument.Type?.IsRefLikeType == true) { escapeTo = Math.Min(escapeTo, GetValEscape(argument, scopeOfTheContainingExpression)); } @@ -2318,7 +2382,7 @@ private bool CheckInvocationArgMixing( // track the widest scope that arguments could safely escape to. // use this scope as the inferred STE of declaration expressions. - var inferredDestinationValEscape = CallingMethodScope; + var inferredDestinationValEscape = Binder.CallingMethodScope; foreach (var (parameter, argument, _) in escapeArguments) { // in the old rules, we assume that refs cannot escape into ref struct variables. @@ -2336,7 +2400,7 @@ private bool CheckInvocationArgMixing( { if (ShouldInferDeclarationExpressionValEscape(argument, out var localSymbol)) { - localSymbol.SetValEscape(inferredDestinationValEscape); + SetLocalScopes(localSymbol, refEscapeScope: _localScopeDepth, valEscapeScope: inferredDestinationValEscape); } } @@ -2419,7 +2483,7 @@ void inferDeclarationExpressionValEscape() { // find the widest scope that arguments could safely escape to. // use this scope as the inferred STE of declaration expressions. - var inferredDestinationValEscape = CallingMethodScope; + var inferredDestinationValEscape = Binder.CallingMethodScope; foreach (var (_, fromArg, _, isRefEscape) in escapeValues) { inferredDestinationValEscape = Math.Max(inferredDestinationValEscape, isRefEscape @@ -2431,7 +2495,7 @@ void inferDeclarationExpressionValEscape() { if (ShouldInferDeclarationExpressionValEscape(argument, out var localSymbol)) { - localSymbol.SetValEscape(inferredDestinationValEscape); + SetLocalScopes(localSymbol, refEscapeScope: _localScopeDepth, valEscapeScope: inferredDestinationValEscape); } } } @@ -2485,7 +2549,10 @@ private static ErrorCode GetStandardCallEscapeError(bool checkingReceiver) { return checkingReceiver ? ErrorCode.ERR_EscapeCall2 : ErrorCode.ERR_EscapeCall; } + } + internal partial class Binder + { private static void ReportReadonlyLocalError(SyntaxNode node, LocalSymbol local, BindValueKind kind, bool checkingReceiver, BindingDiagnosticBag diagnostics) { Debug.Assert((object)local != null); @@ -2628,7 +2695,10 @@ private static ErrorCode GetStandardLvalueError(BindValueKind kind) throw ExceptionUtilities.UnexpectedValue(kind); } + } + internal partial class RefSafetyAnalysis + { private static ErrorCode GetStandardRValueRefEscapeError(uint escapeTo) { if (escapeTo is Binder.CallingMethodScope or Binder.ReturnOnlyScope) @@ -2638,7 +2708,10 @@ private static ErrorCode GetStandardRValueRefEscapeError(uint escapeTo) return ErrorCode.ERR_EscapeOther; } + } + internal partial class Binder + { private static void ReportReadOnlyFieldError(FieldSymbol field, SyntaxNode node, BindValueKind kind, bool checkingReceiver, BindingDiagnosticBag diagnostics) { Debug.Assert((object)field != null); @@ -2707,12 +2780,14 @@ private static void ReportReadOnlyError(Symbol symbol, SyntaxNode node, BindValu int index = (checkingReceiver ? 3 : 0) + (kind == BindValueKind.RefReturn ? 0 : (RequiresRefOrOut(kind) ? 1 : 2)); Error(diagnostics, ReadOnlyErrors[index], node, symbolKind, new FormattedSymbol(symbol, SymbolDisplayFormat.ShortFormat)); } + } + internal partial class RefSafetyAnalysis + { /// - /// Checks whether given expression can escape from the current scope to the - /// In a case if it cannot a bad expression is returned and diagnostics is produced. + /// Checks whether given expression can escape from the current scope to the . /// - internal BoundExpression ValidateEscape(BoundExpression expr, uint escapeTo, bool isByRef, BindingDiagnosticBag diagnostics) + internal void ValidateEscape(BoundExpression expr, uint escapeTo, bool isByRef, BindingDiagnosticBag diagnostics) { // The result of escape analysis is affected by the expression's type. // We can't do escape analysis on expressions which lack a type, such as 'target typed new()', until they are converted. @@ -2720,20 +2795,12 @@ internal BoundExpression ValidateEscape(BoundExpression expr, uint escapeTo, boo if (isByRef) { - if (CheckRefEscape(expr.Syntax, expr, this.LocalScopeDepth, escapeTo, checkingReceiver: false, diagnostics: diagnostics)) - { - return expr; - } + CheckRefEscape(expr.Syntax, expr, _localScopeDepth, escapeTo, checkingReceiver: false, diagnostics: diagnostics); } else { - if (CheckValEscape(expr.Syntax, expr, this.LocalScopeDepth, escapeTo, checkingReceiver: false, diagnostics: diagnostics)) - { - return expr; - } + CheckValEscape(expr.Syntax, expr, _localScopeDepth, escapeTo, checkingReceiver: false, diagnostics: diagnostics); } - - return ToBadExpression(expr); } /// @@ -2758,7 +2825,7 @@ internal uint GetRefEscape(BoundExpression expr, uint scopeOfTheContainingExpres } // constants/literals cannot ref-escape current scope - if (expr.ConstantValue != null) + if (expr.ConstantValueOpt != null) { return scopeOfTheContainingExpression; } @@ -2794,14 +2861,14 @@ internal uint GetRefEscape(BoundExpression expr, uint scopeOfTheContainingExpres return GetParameterRefEscape(((BoundParameter)expr).ParameterSymbol); case BoundKind.Local: - return ((BoundLocal)expr).LocalSymbol.RefEscapeScope; + return GetLocalScopes(((BoundLocal)expr).LocalSymbol).RefEscapeScope; case BoundKind.CapturedReceiverPlaceholder: // Equivalent to a non-ref local with the underlying receiver as an initializer provided at declaration return ((BoundCapturedReceiverPlaceholder)expr).LocalScopeDepth; case BoundKind.ThisReference: - var thisParam = ((MethodSymbol)this.ContainingMember()).ThisParameter; + var thisParam = ((MethodSymbol)_symbol).ThisParameter; Debug.Assert(thisParam.Type.Equals(((BoundThisReference)expr).Type, TypeCompareKind.ConsiderEverything)); return GetParameterRefEscape(thisParam); @@ -3002,7 +3069,7 @@ internal bool CheckRefEscape(SyntaxNode node, BoundExpression expr, uint escapeF } // references to constants/literals cannot escape higher. - if (expr.ConstantValue != null) + if (expr.ConstantValueOpt != null) { Error(diagnostics, GetStandardRValueRefEscapeError(escapeTo), node); return false; @@ -3055,7 +3122,7 @@ internal bool CheckRefEscape(SyntaxNode node, BoundExpression expr, uint escapeF break; case BoundKind.ThisReference: - var thisParam = ((MethodSymbol)this.ContainingMember()).ThisParameter; + var thisParam = ((MethodSymbol)_symbol).ThisParameter; Debug.Assert(thisParam.Type.Equals(((BoundThisReference)expr).Type, TypeCompareKind.ConsiderEverything)); return CheckParameterRefEscape(node, expr, thisParam, escapeTo, checkingReceiver, diagnostics); @@ -3257,6 +3324,17 @@ internal bool CheckRefEscape(SyntaxNode node, BoundExpression expr, uint escapeF escapeTo, checkingReceiver: false, diagnostics); + + case BoundKind.Conversion: + var conversion = (BoundConversion)expr; + if (conversion.Conversion == Conversion.ImplicitThrow) + { + return CheckRefEscape(node, conversion.Operand, escapeFrom, escapeTo, checkingReceiver, diagnostics); + } + break; + + case BoundKind.ThrowExpression: + return true; } // At this point we should have covered all the possible cases for anything that is not a strict RValue. @@ -3299,7 +3377,7 @@ internal uint GetValEscape(BoundExpression expr, uint scopeOfTheContainingExpres } // constants/literals cannot refer to local state - if (expr.ConstantValue != null) + if (expr.ConstantValueOpt != null) { return Binder.CallingMethodScope; } @@ -3315,7 +3393,7 @@ internal uint GetValEscape(BoundExpression expr, uint scopeOfTheContainingExpres switch (expr.Kind) { case BoundKind.ThisReference: - var thisParam = ((MethodSymbol)this.ContainingMember()).ThisParameter; + var thisParam = ((MethodSymbol)_symbol).ThisParameter; Debug.Assert(thisParam.Type.Equals(((BoundThisReference)expr).Type, TypeCompareKind.ConsiderEverything)); return GetParameterValEscape(thisParam); case BoundKind.DefaultLiteral: @@ -3345,13 +3423,15 @@ internal uint GetValEscape(BoundExpression expr, uint scopeOfTheContainingExpres return Binder.CallingMethodScope; case BoundKind.DiscardExpression: - return ((BoundDiscardExpression)expr).ValEscape; + return Binder.CallingMethodScope; case BoundKind.DeconstructValuePlaceholder: - return ((BoundDeconstructValuePlaceholder)expr).ValEscape; + case BoundKind.InterpolatedStringArgumentPlaceholder: + case BoundKind.AwaitableValuePlaceholder: + return GetPlaceholderScope((BoundValuePlaceholderBase)expr); case BoundKind.Local: - return ((BoundLocal)expr).LocalSymbol.ValEscapeScope; + return GetLocalScopes(((BoundLocal)expr).LocalSymbol).ValEscapeScope; case BoundKind.CapturedReceiverPlaceholder: // Equivalent to a non-ref local with the underlying receiver as an initializer provided at declaration @@ -3442,15 +3522,6 @@ internal uint GetValEscape(BoundExpression expr, uint scopeOfTheContainingExpres isRefEscape: false); } - case BoundKind.ImplicitIndexerReceiverPlaceholder: - return ((BoundImplicitIndexerReceiverPlaceholder)expr).ValEscape; - - case BoundKind.ListPatternReceiverPlaceholder: - return ((BoundListPatternReceiverPlaceholder)expr).ValEscape; - - case BoundKind.SlicePatternReceiverPlaceholder: - return ((BoundSlicePatternReceiverPlaceholder)expr).ValEscape; - case BoundKind.ImplicitIndexerAccess: var implicitIndexerAccess = (BoundImplicitIndexerAccess)expr; @@ -3611,18 +3682,11 @@ internal uint GetValEscape(BoundExpression expr, uint scopeOfTheContainingExpres // location. return scopeOfTheContainingExpression; - case BoundKind.InterpolatedStringArgumentPlaceholder: - // We saved off the safe-to-escape of the argument when we did binding - return ((BoundInterpolatedStringArgumentPlaceholder)expr).ValSafeToEscape; - case BoundKind.DisposableValuePlaceholder: // Disposable value placeholder is only ever used to lookup a pattern dispose method // then immediately discarded. The actual expression will be generated during lowering return scopeOfTheContainingExpression; - case BoundKind.AwaitableValuePlaceholder: - return ((BoundAwaitableValuePlaceholder)expr).ValEscape; - case BoundKind.PointerElementAccess: case BoundKind.PointerIndirectionOperator: // Unsafe code will always be allowed to escape. @@ -3720,7 +3784,7 @@ internal bool CheckValEscape(SyntaxNode node, BoundExpression expr, uint escapeF } // constants/literals cannot refer to local state - if (expr.ConstantValue != null) + if (expr.ConstantValueOpt != null) { return true; } @@ -3731,12 +3795,12 @@ internal bool CheckValEscape(SyntaxNode node, BoundExpression expr, uint escapeF return true; } - bool inUnsafeRegion = this.InUnsafeRegion; + bool inUnsafeRegion = _inUnsafeRegion; switch (expr.Kind) { case BoundKind.ThisReference: - var thisParam = ((MethodSymbol)this.ContainingMember()).ThisParameter; + var thisParam = ((MethodSymbol)_symbol).ThisParameter; Debug.Assert(thisParam.Type.Equals(((BoundThisReference)expr).Type, TypeCompareKind.ConsiderEverything)); return CheckParameterValEscape(node, thisParam, escapeTo, diagnostics); @@ -3764,23 +3828,9 @@ internal bool CheckValEscape(SyntaxNode node, BoundExpression expr, uint escapeF return true; case BoundKind.DeconstructValuePlaceholder: - if (((BoundDeconstructValuePlaceholder)expr).ValEscape > escapeTo) - { - Error(diagnostics, inUnsafeRegion ? ErrorCode.WRN_EscapeVariable : ErrorCode.ERR_EscapeVariable, node, expr.Syntax); - return inUnsafeRegion; - } - return true; - case BoundKind.AwaitableValuePlaceholder: - if (((BoundAwaitableValuePlaceholder)expr).ValEscape > escapeTo) - { - Error(diagnostics, inUnsafeRegion ? ErrorCode.WRN_EscapeVariable : ErrorCode.ERR_EscapeVariable, node, expr.Syntax); - return inUnsafeRegion; - } - return true; - case BoundKind.InterpolatedStringArgumentPlaceholder: - if (((BoundInterpolatedStringArgumentPlaceholder)expr).ValSafeToEscape > escapeTo) + if (GetPlaceholderScope((BoundValuePlaceholderBase)expr) > escapeTo) { Error(diagnostics, inUnsafeRegion ? ErrorCode.WRN_EscapeVariable : ErrorCode.ERR_EscapeVariable, node, expr.Syntax); return inUnsafeRegion; @@ -3789,7 +3839,7 @@ internal bool CheckValEscape(SyntaxNode node, BoundExpression expr, uint escapeF case BoundKind.Local: var localSymbol = ((BoundLocal)expr).LocalSymbol; - if (localSymbol.ValEscapeScope > escapeTo) + if (GetLocalScopes(localSymbol).ValEscapeScope > escapeTo) { Error(diagnostics, inUnsafeRegion ? ErrorCode.WRN_EscapeVariable : ErrorCode.ERR_EscapeVariable, node, localSymbol); return inUnsafeRegion; @@ -3910,30 +3960,6 @@ internal bool CheckValEscape(SyntaxNode node, BoundExpression expr, uint escapeF isRefEscape: false); } - case BoundKind.ImplicitIndexerReceiverPlaceholder: - if (((BoundImplicitIndexerReceiverPlaceholder)expr).ValEscape > escapeTo) - { - Error(diagnostics, inUnsafeRegion ? ErrorCode.WRN_EscapeVariable : ErrorCode.ERR_EscapeVariable, node, expr.Syntax); - return inUnsafeRegion; - } - return true; - - case BoundKind.ListPatternReceiverPlaceholder: - if (((BoundListPatternReceiverPlaceholder)expr).ValEscape > escapeTo) - { - Error(diagnostics, inUnsafeRegion ? ErrorCode.WRN_EscapeVariable : ErrorCode.ERR_EscapeVariable, node, expr.Syntax); - return inUnsafeRegion; - } - return true; - - case BoundKind.SlicePatternReceiverPlaceholder: - if (((BoundSlicePatternReceiverPlaceholder)expr).ValEscape > escapeTo) - { - Error(diagnostics, inUnsafeRegion ? ErrorCode.WRN_EscapeVariable : ErrorCode.ERR_EscapeVariable, node, expr.Syntax); - return inUnsafeRegion; - } - return true; - case BoundKind.ImplicitIndexerAccess: var implicitIndexerAccess = (BoundImplicitIndexerAccess)expr; @@ -4418,8 +4444,8 @@ void getParts(BoundInterpolatedString interpolatedString) // SPEC: For a given argument `a` that is passed to parameter `p`: // SPEC: 1. ... // SPEC: 2. If `p` is `scoped` then `a` does not contribute *safe-to-escape* when considering arguments. - if (UseUpdatedEscapeRules && - call.Method.Parameters[0].EffectiveScope == DeclarationScope.ValueScoped) + if (_useUpdatedEscapeRules && + call.Method.Parameters[0].EffectiveScope == ScopedKind.ScopedValue) { continue; } @@ -4428,7 +4454,10 @@ void getParts(BoundInterpolatedString interpolatedString) } } } + } + internal partial class Binder + { internal enum AddressKind { // reference may be written to @@ -4550,6 +4579,21 @@ internal static bool HasHome( stackLocalsOpt)); goto case BoundKind.ConditionalReceiver; + case BoundKind.ComplexReceiver: + Debug.Assert(HasHome( + ((BoundComplexReceiver)expression).ValueTypeReceiver, + addressKind, + containingSymbol, + peVerifyCompatEnabled, + stackLocalsOpt)); + Debug.Assert(HasHome( + ((BoundComplexReceiver)expression).ReferenceTypeReceiver, + addressKind, + containingSymbol, + peVerifyCompatEnabled, + stackLocalsOpt)); + goto case BoundKind.ConditionalReceiver; + case BoundKind.ConditionalReceiver: //ConditionalReceiver is a noop from Emit point of view. - it represents something that has already been pushed. //We should never need a temp for it. diff --git a/src/Compilers/CSharp/Portable/Binder/Binder.cs b/src/Compilers/CSharp/Portable/Binder/Binder.cs index f5b1a6aa5fa1e..fd01285289f2b 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder.cs @@ -810,6 +810,21 @@ internal static void ReportUseSiteDiagnosticForSynthesizedAttribute( GetWellKnownTypeMember(compilation, attributeMember, diagnostics, location, syntax, isOptional); } + /// + /// Adds diagnostics that should be reported when using a synthesized attribute. + /// + internal static void AddUseSiteDiagnosticForSynthesizedAttribute( + CSharpCompilation compilation, + WellKnownMember attributeMember, + ref CompoundUseSiteInfo useSiteInfo) + { + GetWellKnownTypeMember(compilation, + attributeMember, + out var memberUseSiteInfo, + isOptional: WellKnownMembers.IsSynthesizedAttributeOptional(attributeMember)); + useSiteInfo.Add(memberUseSiteInfo); + } + public CompoundUseSiteInfo GetNewCompoundUseSiteInfo(BindingDiagnosticBag futureDestination) { return new CompoundUseSiteInfo(futureDestination, Compilation.Assembly); @@ -867,7 +882,7 @@ internal BoundStatement WrapWithVariablesAndLocalFunctionsIfAny(CSharpSyntaxNode return statement; } - return new BoundBlock(statement.Syntax, locals, localFunctions, + return new BoundBlock(statement.Syntax, locals, localFunctions, hasUnsafeModifier: false, ImmutableArray.Create(statement)) { WasCompilerGenerated = true }; } diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_AnonymousTypes.cs b/src/Compilers/CSharp/Portable/Binder/Binder_AnonymousTypes.cs index 0e4b5a88463f1..d8373936fba69 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_AnonymousTypes.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_AnonymousTypes.cs @@ -94,7 +94,7 @@ private BoundExpression BindAnonymousObjectCreation(AnonymousObjectCreationExpre fieldSyntaxNodes[i].Location, TypeWithAnnotations.Create(fieldType), RefKind.None, - DeclarationScope.Unscoped); + ScopedKind.None); // NOTE: ERR_InvalidAnonymousTypeMemberDeclarator (CS0746) would be generated by parser if needed } diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs index b6e63f58fdbc1..e8f3afa1ee7bd 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs @@ -941,7 +941,7 @@ private TypedConstant VisitExpression(BoundExpression node, TypedConstantKind ty { // Validate Statement 2) of the spec comment above. - ConstantValue? constantValue = node.ConstantValue; + ConstantValue? constantValue = node.ConstantValueOpt; if (constantValue != null) { if (constantValue.IsBad) @@ -969,7 +969,7 @@ private TypedConstant VisitExpression(BoundExpression node, TypedConstantKind ty private TypedConstant VisitConversion(BoundConversion node, BindingDiagnosticBag diagnostics, ref bool attrHasErrors, bool curArgumentHasErrors) { - Debug.Assert(node.ConstantValue == null); + Debug.Assert(node.ConstantValueOpt == null); // We have a bound conversion with a non-constant value. // According to statement 2) of the spec comment, this is not a valid attribute argument. diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Await.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Await.cs index ffc9012e02949..43d1f98cf1ef0 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Await.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Await.cs @@ -29,7 +29,7 @@ private BoundExpression BindAwait(AwaitExpressionSyntax node, BindingDiagnosticB private BoundAwaitExpression BindAwait(BoundExpression expression, SyntaxNode node, BindingDiagnosticBag diagnostics) { bool hasErrors = false; - var placeholder = new BoundAwaitableValuePlaceholder(expression.Syntax, GetValEscape(expression, LocalScopeDepth), expression.Type); + var placeholder = new BoundAwaitableValuePlaceholder(expression.Syntax, expression.Type); ReportBadAwaitDiagnostics(node, node.Location, diagnostics, ref hasErrors); var info = BindAwaitInfo(placeholder, node, diagnostics, ref hasErrors, expressionOpt: expression); diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs index 37e14edf5383f..98ec8469d0bb2 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs @@ -163,7 +163,7 @@ BoundExpression createConversion( CheckOverflowAtRuntime, explicitCastInCode: isCast && !wasCompilerGenerated, conversionGroupOpt, - convertedSwitch.ConstantValue, + convertedSwitch.ConstantValueOpt, destination, hasErrors); } @@ -178,7 +178,7 @@ BoundExpression createConversion( CheckOverflowAtRuntime, explicitCastInCode: isCast && !wasCompilerGenerated, conversionGroupOpt, - convertedConditional.ConstantValue, + convertedConditional.ConstantValueOpt, destination, hasErrors); } @@ -190,7 +190,7 @@ BoundExpression createConversion( unconvertedSource.Syntax, interpolationData: null, BindInterpolatedStringParts(unconvertedSource, diagnostics), - unconvertedSource.ConstantValue, + unconvertedSource.ConstantValueOpt, unconvertedSource.Type, unconvertedSource.HasErrors); } @@ -365,7 +365,7 @@ private static BoundExpression ConvertObjectCreationExpression( node.Binder.CheckOverflowAtRuntime, explicitCastInCode: isCast && !wasCompilerGenerated, conversionGroupOpt, - expr.ConstantValue, + expr.ConstantValueOpt, destination) { WasCompilerGenerated = wasCompilerGenerated }; @@ -774,18 +774,11 @@ private static void CheckValidScopedMethodConversion(SyntaxNode syntax, MethodSy } } - /// - /// Warns for defaults/`params` mismatch. - /// private static void CheckLambdaConversion(LambdaSymbol lambdaSymbol, TypeSymbol targetType, BindingDiagnosticBag diagnostics) { - if (lambdaSymbol.SyntaxNode.IsKind(SyntaxKind.AnonymousMethodExpression)) - { - return; - } - var delegateType = targetType.GetDelegateType(); Debug.Assert(delegateType is not null); + var isSynthesized = delegateType.DelegateInvokeMethod?.OriginalDefinition is SynthesizedDelegateInvokeMethod; var delegateParameters = delegateType.DelegateParameters(); Debug.Assert(lambdaSymbol.ParameterCount == delegateParameters.Length); @@ -794,23 +787,79 @@ private static void CheckLambdaConversion(LambdaSymbol lambdaSymbol, TypeSymbol var lambdaParameter = lambdaSymbol.Parameters[p]; var delegateParameter = delegateParameters[p]; - if (lambdaParameter.HasExplicitDefaultValue && - lambdaParameter.ExplicitDefaultConstantValue is { IsBad: false } lambdaParamDefault) + if (isSynthesized) { - var delegateParamDefault = delegateParameter.HasExplicitDefaultValue ? delegateParameter.ExplicitDefaultConstantValue : null; - if (delegateParamDefault?.IsBad != true && lambdaParamDefault != delegateParamDefault) + // If synthesizing a delegate with `decimal`/`DateTime` default value, + // check that the corresponding `*ConstantAttribute` is available. + if (delegateParameter.ExplicitDefaultConstantValue is { } defaultValue && + // Skip reporting this diagnostic if already reported in `SourceComplexParameterSymbolBase.DefaultSyntaxValue`. + lambdaParameter is not SourceComplexParameterSymbolBase + { + ExplicitDefaultConstantValue.IsDecimal: true, + DefaultValueFromAttributes: ConstantValue.NotAvailable + }) + { + WellKnownMember? member = defaultValue.SpecialType switch + { + SpecialType.System_Decimal => WellKnownMember.System_Runtime_CompilerServices_DecimalConstantAttribute__ctor, + SpecialType.System_DateTime => WellKnownMember.System_Runtime_CompilerServices_DateTimeConstantAttribute__ctor, + _ => null + }; + if (member != null) + { + reportUseSiteDiagnosticForSynthesizedAttribute( + lambdaSymbol, + lambdaParameter, + member.GetValueOrDefault(), + diagnostics); + } + } + + // If synthesizing a delegate with an [UnscopedRef] parameter, check the attribute is available. + if (delegateParameter.HasUnscopedRefAttribute) { - // Parameter {0} has default value '{1}' in lambda but '{2}' in target delegate type. - Error(diagnostics, ErrorCode.WRN_OptionalParamValueMismatch, lambdaParameter.Locations[0], p + 1, lambdaParamDefault, delegateParamDefault ?? ((object)MessageID.IDS_Missing.Localize())); + reportUseSiteDiagnosticForSynthesizedAttribute( + lambdaSymbol, + lambdaParameter, + WellKnownMember.System_Diagnostics_CodeAnalysis_UnscopedRefAttribute__ctor, + diagnostics); } } - if (lambdaParameter.IsParams && !delegateParameter.IsParams && p == lambdaSymbol.ParameterCount - 1 && lambdaParameter.Type.IsSZArray()) + // Warn for defaults/`params` mismatch. + if (!lambdaSymbol.SyntaxNode.IsKind(SyntaxKind.AnonymousMethodExpression)) { - // Parameter {0} has params modifier in lambda but not in target delegate type. - Error(diagnostics, ErrorCode.WRN_ParamsArrayInLambdaOnly, lambdaParameter.Locations[0], p + 1); + if (lambdaParameter.HasExplicitDefaultValue && + lambdaParameter.ExplicitDefaultConstantValue is { IsBad: false } lambdaParamDefault) + { + var delegateParamDefault = delegateParameter.HasExplicitDefaultValue ? delegateParameter.ExplicitDefaultConstantValue : null; + if (delegateParamDefault?.IsBad != true && lambdaParamDefault != delegateParamDefault) + { + // Parameter {0} has default value '{1}' in lambda but '{2}' in target delegate type. + Error(diagnostics, ErrorCode.WRN_OptionalParamValueMismatch, lambdaParameter.Locations[0], p + 1, lambdaParamDefault, delegateParamDefault ?? ((object)MessageID.IDS_Missing.Localize())); + } + } + + if (lambdaParameter.IsParams && !delegateParameter.IsParams && p == lambdaSymbol.ParameterCount - 1 && lambdaParameter.Type.IsSZArray()) + { + // Parameter {0} has params modifier in lambda but not in target delegate type. + Error(diagnostics, ErrorCode.WRN_ParamsArrayInLambdaOnly, lambdaParameter.Locations[0], p + 1); + } } } + + static void reportUseSiteDiagnosticForSynthesizedAttribute( + LambdaSymbol lambdaSymbol, + ParameterSymbol lambdaParameter, + WellKnownMember member, + BindingDiagnosticBag diagnostics) + { + ReportUseSiteDiagnosticForSynthesizedAttribute( + lambdaSymbol.DeclaringCompilation, + member, + diagnostics, + lambdaParameter.Locations.FirstOrDefault() ?? lambdaSymbol.SyntaxNode.Location); + } } private BoundExpression CreateStackAllocConversion(SyntaxNode syntax, BoundExpression source, Conversion conversion, bool isCast, ConversionGroup? conversionGroup, TypeSymbol destination, BindingDiagnosticBag diagnostics) @@ -1513,7 +1562,7 @@ private bool MethodGroupConversionDoesNotExistOrHasErrors( // TODO: Some conversions can produce errors or warnings depending on checked/unchecked. // TODO: Fold conversions on enums and strings too. - var sourceConstantValue = source.ConstantValue; + var sourceConstantValue = source.ConstantValueOpt; if (sourceConstantValue == null) { if (conversion.Kind == ConversionKind.DefaultLiteral) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Deconstruct.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Deconstruct.cs index 68dadfd4275ea..4e6dd7fc007c1 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Deconstruct.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Deconstruct.cs @@ -118,12 +118,11 @@ private BoundDeconstructionAssignmentOperator BindDeconstructionAssignment( BindingDiagnosticBag diagnostics) { Debug.Assert(diagnostics.DiagnosticBag is object); - uint rightEscape = GetValEscape(boundRHS, this.LocalScopeDepth); if ((object?)boundRHS.Type == null || boundRHS.Type.IsErrorType()) { // we could still not infer a type for the RHS - FailRemainingInferencesAndSetValEscape(checkedVariables, diagnostics, rightEscape); + FailRemainingInferences(checkedVariables, diagnostics); var voidType = GetSpecialType(SpecialType.System_Void, diagnostics, node); var type = boundRHS.Type ?? voidType; @@ -144,7 +143,6 @@ private BoundDeconstructionAssignmentOperator BindDeconstructionAssignment( boundRHS.Type, node, boundRHS.Syntax, - rightEscape, diagnostics, checkedVariables, out conversion); @@ -154,7 +152,7 @@ private BoundDeconstructionAssignmentOperator BindDeconstructionAssignment( CheckImplicitThisCopyInReadOnlyMember(boundRHS, conversion.Method, diagnostics); } - FailRemainingInferencesAndSetValEscape(checkedVariables, diagnostics, rightEscape); + FailRemainingInferences(checkedVariables, diagnostics); var lhsTuple = DeconstructionVariablesAsTuple(left, checkedVariables, diagnostics, ignoreDiagnosticsFromTuple: diagnostics.HasAnyErrors() || !resultIsUsed); Debug.Assert(hasErrors || lhsTuple.Type is object); @@ -245,7 +243,6 @@ private bool MakeDeconstructionConversion( TypeSymbol type, SyntaxNode syntax, SyntaxNode rightSyntax, - uint rightValEscape, BindingDiagnosticBag diagnostics, ArrayBuilder variables, out Conversion conversion) @@ -276,7 +273,7 @@ private bool MakeDeconstructionConversion( return false; } - var inputPlaceholder = new BoundDeconstructValuePlaceholder(syntax, variableSymbol: null, rightValEscape, type); + var inputPlaceholder = new BoundDeconstructValuePlaceholder(syntax, variableSymbol: null, isDiscardExpression: false, type); BoundExpression deconstructInvocation = MakeDeconstructInvocationExpression(variables.Count, inputPlaceholder, rightSyntax, diagnostics, outPlaceholders: out ImmutableArray outPlaceholders, out _, variables); @@ -305,7 +302,7 @@ private bool MakeDeconstructionConversion( { var elementSyntax = syntax.Kind() == SyntaxKind.TupleExpression ? ((TupleExpressionSyntax)syntax).Arguments[i] : syntax; - hasErrors |= !MakeDeconstructionConversion(tupleOrDeconstructedTypes[i], elementSyntax, rightSyntax, rightValEscape, diagnostics, + hasErrors |= !MakeDeconstructionConversion(tupleOrDeconstructedTypes[i], elementSyntax, rightSyntax, diagnostics, variable.NestedVariables, out nestedConversion); Debug.Assert(nestedConversion.Kind == ConversionKind.Deconstruction); @@ -391,8 +388,7 @@ private BoundExpression SetInferredType(BoundExpression expression, TypeSymbol t /// Find any deconstruction locals that are still pending inference and fail their inference. /// Set the safe-to-escape scope for all deconstruction locals. /// - private void FailRemainingInferencesAndSetValEscape(ArrayBuilder variables, BindingDiagnosticBag diagnostics, - uint rhsValEscape) + private void FailRemainingInferences(ArrayBuilder variables, BindingDiagnosticBag diagnostics) { int count = variables.Count; for (int i = 0; i < count; i++) @@ -400,21 +396,13 @@ private void FailRemainingInferencesAndSetValEscape(ArrayBuilder symbol, BoundLocal { DeclarationKind: BoundLocalDeclarationKind.WithExplicitType or BoundLocalDeclarationKind.WithInferredType, LocalSymbol: var symbol } => symbol, _ => null, }; - var variable = new OutDeconstructVarPendingInference(receiverSyntax, variableSymbol: variableSymbol, valEscape); + var variable = new OutDeconstructVarPendingInference(receiverSyntax, variableSymbol: variableSymbol, isDiscardExpression: variableOpt is BoundDiscardExpression); analyzedArguments.Arguments.Add(variable); analyzedArguments.RefKinds.Add(RefKind.Out); outVars.Add(variable); @@ -865,8 +852,7 @@ private BoundDiscardExpression BindDiscardExpression( SyntaxNode syntax, TypeWithAnnotations declTypeWithAnnotations) { - // Cannot escape out of the current expression, as it's a compiler-synthesized location. - return new BoundDiscardExpression(syntax, LocalScopeDepth, declTypeWithAnnotations.Type); + return new BoundDiscardExpression(syntax, declTypeWithAnnotations.Type); } /// @@ -902,7 +888,7 @@ private BoundExpression BindDeconstructionVariable( } if (declTypeWithAnnotations.HasType && - localSymbol.Scope == DeclarationScope.ValueScoped && !declTypeWithAnnotations.Type.IsErrorTypeOrRefLikeType()) + localSymbol.Scope == ScopedKind.ScopedValue && !declTypeWithAnnotations.Type.IsErrorTypeOrRefLikeType()) { diagnostics.Add(ErrorCode.ERR_ScopedRefAndRefStructOnly, typeSyntax.Location); } diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index 70294f9642ea1..15f690f2a48eb 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -353,7 +353,7 @@ internal BoundExpression BindToNaturalType(BoundExpression expression, BindingDi result = new BoundDefaultExpression( defaultExpr.Syntax, targetType: null, - defaultExpr.ConstantValue, + defaultExpr.ConstantValueOpt, CreateErrorType(), hasErrors: true).WithSuppression(defaultExpr.IsSuppressed); } @@ -804,9 +804,9 @@ private BoundExpression BindExpressionInternal(ExpressionSyntax node, BindingDia } #nullable enable - internal virtual BoundSwitchExpressionArm BindSwitchExpressionArm(SwitchExpressionArmSyntax node, TypeSymbol switchGoverningType, uint switchGoverningValEscape, BindingDiagnosticBag diagnostics) + internal virtual BoundSwitchExpressionArm BindSwitchExpressionArm(SwitchExpressionArmSyntax node, TypeSymbol switchGoverningType, BindingDiagnosticBag diagnostics) { - return this.NextRequired.BindSwitchExpressionArm(node, switchGoverningType, switchGoverningValEscape, diagnostics); + return this.NextRequired.BindSwitchExpressionArm(node, switchGoverningType, diagnostics); } #nullable disable @@ -1580,8 +1580,7 @@ private BoundExpression BindIdentifier( } else if (FallBackOnDiscard(identifier, diagnostics)) { - // Cannot escape out of the current expression, as it's a compiler-synthesized location. - expression = new BoundDiscardExpression(node, LocalScopeDepth, type: null); + expression = new BoundDiscardExpression(node, type: null); } } @@ -2687,7 +2686,7 @@ private BoundExpression BindExplicitNullableCastFromNonNullable(ExpressionSyntax // It's possible for the S -> T conversion to produce a 'better' constant value. If this // constant value is produced place it in the tree so that it gets emitted. This maintains // parity with the native compiler which also evaluated the conversion at compile time. - if (underlyingExpr.ConstantValue != null && + if (underlyingExpr.ConstantValueOpt != null && !underlyingExpr.HasErrors && !bag.HasAnyErrors()) { underlyingExpr.WasCompilerGenerated = true; @@ -2917,8 +2916,7 @@ private BoundExpression BindOutDeclarationArgument(DeclarationExpressionSyntax d var declType = BindVariableTypeWithAnnotations(designation, diagnostics, typeSyntax, ref isConst, out isVar, out alias); Debug.Assert(isVar != declType.HasType); - // ValEscape is the same as for an uninitialized local - return new BoundDiscardExpression(declarationExpression, Binder.CallingMethodScope, declType.Type); + return new BoundDiscardExpression(declarationExpression, declType.Type); } case SyntaxKind.SingleVariableDesignation: return BindOutVariableDeclarationArgument(declarationExpression, diagnostics); @@ -2972,7 +2970,7 @@ private BoundExpression BindOutVariableDeclarationArgument( CheckRestrictedTypeInAsyncMethod(this.ContainingMemberOrLambda, declType.Type, diagnostics, typeSyntax); - if (localSymbol.Scope == DeclarationScope.ValueScoped && !declType.Type.IsErrorTypeOrRefLikeType()) + if (localSymbol.Scope == ScopedKind.ScopedValue && !declType.Type.IsErrorTypeOrRefLikeType()) { diagnostics.Add(ErrorCode.ERR_ScopedRefAndRefStructOnly, typeSyntax.Location); } @@ -3182,7 +3180,7 @@ private void CoerceArguments( Debug.Assert(argument is BoundUnconvertedInterpolatedString or BoundBinaryOperator { IsUnconvertedInterpolatedStringAddition: true }); TypeWithAnnotations parameterTypeWithAnnotations = GetCorrespondingParameterTypeWithAnnotations(ref result, parameters, arg); reportUnsafeIfNeeded(methodResult, diagnostics, argument, parameterTypeWithAnnotations); - arguments[arg] = BindInterpolatedStringHandlerInMemberCall(argument, arguments, parameters, ref result, arg, receiver, methodResult.LeastOverriddenMember.RequiresInstanceReceiver(), diagnostics); + arguments[arg] = BindInterpolatedStringHandlerInMemberCall(argument, arguments, parameters, ref result, arg, receiver, diagnostics); } // https://github.com/dotnet/roslyn/issues/37119 : should we create an (Identity) conversion when the kind is Identity but the types differ? else if (!kind.IsIdentity) @@ -4013,7 +4011,7 @@ private BoundExpression BindStackAllocWithInitializer( return null; } - var constantValue = expression.ConstantValue; + var constantValue = expression.ConstantValueOpt; if (constantValue == null || constantValue.IsBad || expression.Type.SpecialType != SpecialType.System_Int32) { @@ -4032,7 +4030,7 @@ private static bool IsNegativeConstantForArraySize(BoundExpression expression) return false; } - var constantValue = expression.ConstantValue; + var constantValue = expression.ConstantValueOpt; if (constantValue == null || constantValue.IsBad) { return false; @@ -4285,19 +4283,6 @@ private BoundExpression BindConstructorInitializerCore( var arguments = analyzedArguments.Arguments.ToImmutable(); var refKinds = analyzedArguments.RefKinds.ToImmutableOrNull(); - if (!hasErrors) - { - hasErrors = !CheckInvocationArgMixing( - nonNullSyntax, - resultMember, - receiver, - resultMember.Parameters, - arguments, - refKinds, - argsToParamsOpt, - this.LocalScopeDepth, - diagnostics); - } if (resultMember.HasSetsRequiredMembers && !constructor.HasSetsRequiredMembers) { @@ -4873,10 +4858,7 @@ private BoundExpression BindInitializerMemberAssignment( diagnostics: diagnostics); // Bind member initializer assignment expression - // We don't verify escape safety of initializers against the instance because the initializers - // get factored in when determining the safe-to-escape of the instance (the initializers contribute - // like constructor arguments). - return BindAssignment(initializer, boundLeft, boundRight, isRef, verifyEscapeSafety: false, diagnostics); + return BindAssignment(initializer, boundLeft, boundRight, isRef, diagnostics); } } @@ -5712,20 +5694,6 @@ protected BoundExpression BindClassCreationExpression( var arguments = analyzedArguments.Arguments.ToImmutable(); var refKinds = analyzedArguments.RefKinds.ToImmutableOrNull(); - if (!hasError) - { - hasError = !CheckInvocationArgMixing( - node, - method, - null, - method.Parameters, - arguments, - refKinds, - argToParams, - this.LocalScopeDepth, - diagnostics); - } - boundInitializerOpt = makeBoundInitializerOpt(); var creation = new BoundObjectCreationExpression( node, @@ -6798,7 +6766,7 @@ BoundExpression tryBindMemberAccessWithBoundTypeLeft( private void WarnOnAccessOfOffDefault(SyntaxNode node, BoundExpression boundLeft, BindingDiagnosticBag diagnostics) { - if ((boundLeft is BoundDefaultLiteral || boundLeft is BoundDefaultExpression) && boundLeft.ConstantValue == ConstantValue.Null && + if ((boundLeft is BoundDefaultLiteral || boundLeft is BoundDefaultExpression) && boundLeft.ConstantValueOpt == ConstantValue.Null && Compilation.LanguageVersion < MessageID.IDS_FeatureNullableReferenceTypes.RequiredVersion()) { Error(diagnostics, ErrorCode.WRN_DotOnDefault, node, boundLeft.Type); @@ -7563,7 +7531,7 @@ protected BoundExpression BindFieldAccess( @checked: true, explicitCastInCode: false, conversionGroupOpt: null, - constantValueOpt: expr.ConstantValue, + constantValueOpt: expr.ConstantValueOpt, type: underlyingType); } } @@ -8006,7 +7974,7 @@ private BoundExpression BindArrayAccess(SyntaxNode node, BoundExpression expr, A // Answer: Because multidimensional arrays can have nonzero lower bounds in the CLR. if (rank == 1 && !index.HasAnyErrors) { - ConstantValue constant = index.ConstantValue; + ConstantValue constant = index.ConstantValueOpt; if (constant != null && constant.IsNegativeNumeric) { Error(diagnostics, ErrorCode.WRN_NegativeArrayIndex, index.Syntax); @@ -8023,7 +7991,7 @@ private BoundExpression BindArrayAccess(SyntaxNode node, BoundExpression expr, A Debug.Assert(convertedArguments.Length == 1); var int32 = GetSpecialType(SpecialType.System_Int32, diagnostics, node); - var receiverPlaceholder = new BoundImplicitIndexerReceiverPlaceholder(expr.Syntax, GetValEscape(expr, LocalScopeDepth), isEquivalentToThisReference: expr.IsEquivalentToThisReference, expr.Type) { WasCompilerGenerated = true }; + var receiverPlaceholder = new BoundImplicitIndexerReceiverPlaceholder(expr.Syntax, isEquivalentToThisReference: expr.IsEquivalentToThisReference, expr.Type) { WasCompilerGenerated = true }; var argumentPlaceholders = ImmutableArray.Create(new BoundImplicitIndexerValuePlaceholder(convertedArguments[0].Syntax, int32) { WasCompilerGenerated = true }); return new BoundImplicitIndexerAccess( @@ -8490,20 +8458,6 @@ private BoundExpression BindIndexerOrIndexedPropertyAccess( var arguments = analyzedArguments.Arguments.ToImmutable(); - if (!gotError) - { - gotError = !CheckInvocationArgMixing( - syntax, - property, - receiver, - property.Parameters, - arguments, - argumentRefKinds, - argsToParams, - this.LocalScopeDepth, - diagnostics); - } - // Note that we do not bind default arguments here, because at this point we do not know whether // the indexer is being used in a 'get', or 'set', or 'get+set' (compound assignment) context. propertyAccess = new BoundIndexerAccess( @@ -8559,8 +8513,7 @@ private bool TryBindIndexOrRangeImplicitIndexer( } bool argIsIndex = argIsIndexNotRange.Value(); - var receiverValEscape = GetValEscape(receiver, LocalScopeDepth); - var receiverPlaceholder = new BoundImplicitIndexerReceiverPlaceholder(receiver.Syntax, receiverValEscape, isEquivalentToThisReference: receiver.IsEquivalentToThisReference, receiver.Type) { WasCompilerGenerated = true }; + var receiverPlaceholder = new BoundImplicitIndexerReceiverPlaceholder(receiver.Syntax, isEquivalentToThisReference: receiver.IsEquivalentToThisReference, receiver.Type) { WasCompilerGenerated = true }; if (!TryBindIndexOrRangeImplicitIndexerParts(syntax, receiverPlaceholder, argIsIndex: argIsIndex, out var lengthOrCountAccess, out var indexerOrSliceAccess, out var argumentPlaceholders, diagnostics)) { @@ -9190,7 +9143,8 @@ static bool isCandidateUnique(ref MethodSymbol? method, MethodSymbol candidate) internal NamedTypeSymbol? GetMethodGroupOrLambdaDelegateType( SyntaxNode syntax, MethodSymbol methodSymbol, - ImmutableArray? parameterScopesOverride = null, + ImmutableArray? parameterScopesOverride = null, + ImmutableArray? parameterHasUnscopedRefAttributesOverride = null, RefKind? returnRefKindOverride = null, TypeWithAnnotations? returnTypeOverride = null) { @@ -9200,9 +9154,9 @@ static bool isCandidateUnique(ref MethodSymbol? method, MethodSymbol candidate) var returnType = returnTypeOverride ?? methodSymbol.ReturnTypeWithAnnotations; var returnRefKind = returnRefKindOverride ?? methodSymbol.RefKind; var parameterScopes = parameterScopesOverride ?? - (parameters.Any(p => p.EffectiveScope != DeclarationScope.Unscoped) ? - parameters.SelectAsArray(p => p.EffectiveScope) : - default); + (parameters.Any(p => p.EffectiveScope != ScopedKind.None) ? parameters.SelectAsArray(p => p.EffectiveScope) : default); + var parameterHasUnscopedRefAttributes = parameterHasUnscopedRefAttributesOverride ?? + (parameters.Any(p => p.HasUnscopedRefAttribute) ? parameters.SelectAsArray(p => p.HasUnscopedRefAttribute) : default); var parameterDefaultValues = parameters.Any(p => p.HasExplicitDefaultValue) ? parameters.SelectAsArray(p => p.ExplicitDefaultConstantValue) : default; @@ -9234,7 +9188,8 @@ static bool isCandidateUnique(ref MethodSymbol? method, MethodSymbol candidate) returnRefKind == RefKind.None && parameterDefaultValues.IsDefault && (parameterRefKinds.IsDefault || parameterRefKinds.All(refKind => refKind == RefKind.None)) && - (parameterScopes.IsDefault || parameterScopes.All(scope => scope == DeclarationScope.Unscoped))) + (parameterScopes.IsDefault || parameterScopes.All(scope => scope == ScopedKind.None)) && + (parameterHasUnscopedRefAttributes.IsDefault || parameterHasUnscopedRefAttributes.All(p => !p))) { var wkDelegateType = returnsVoid ? WellKnownTypes.GetWellKnownActionDelegate(invokeArgumentCount: parameterTypes.Length) : @@ -9267,12 +9222,12 @@ static bool isCandidateUnique(ref MethodSymbol? method, MethodSymbol candidate) location, parameterTypes[i], parameterRefKinds.IsDefault ? RefKind.None : parameterRefKinds[i], - parameterScopes.IsDefault ? DeclarationScope.Unscoped : parameterScopes[i], + parameterScopes.IsDefault ? ScopedKind.None : parameterScopes[i], parameterDefaultValues.IsDefault ? null : parameterDefaultValues[i], - isParams: hasParamsArray && i == parameterTypes.Length - 1) - ); + isParams: hasParamsArray && i == parameterTypes.Length - 1, + hasUnscopedRefAttribute: parameterHasUnscopedRefAttributes.IsDefault ? false : parameterHasUnscopedRefAttributes[i])); } - fieldsBuilder.Add(new AnonymousTypeField(name: "", location, returnType, returnRefKind, DeclarationScope.Unscoped)); + fieldsBuilder.Add(new AnonymousTypeField(name: "", location, returnType, returnRefKind, ScopedKind.None)); var typeDescr = new AnonymousTypeDescriptor(fieldsBuilder.ToImmutableAndFree(), location); return Compilation.AnonymousTypeManager.ConstructAnonymousDelegateSymbol(typeDescr); diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Initializers.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Initializers.cs index 1cacb27913eea..b8e9ecaf84cde 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Initializers.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Initializers.cs @@ -114,18 +114,6 @@ internal static void BindRegularCSharpFieldInitializers( parentBinder = parentBinder.GetFieldInitializerBinder(fieldSymbol); BoundFieldEqualsValue boundInitializer = BindFieldInitializer(parentBinder, fieldSymbol, initializerNode, diagnostics); - - if (!boundInitializer.Value.HasAnyErrors) - { - var field = boundInitializer.Field; - bool isByRef = field.RefKind != RefKind.None; - if (isByRef || field.Type.IsRefLikeType) - { - BoundExpression value = parentBinder.ValidateEscape(boundInitializer.Value, CallingMethodScope, isByRef: isByRef, diagnostics); - boundInitializer = boundInitializer.Update(field, boundInitializer.Locals, value); - } - } - boundInitializers.Add(boundInitializer); break; diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_InterpolatedString.cs b/src/Compilers/CSharp/Portable/Binder/Binder_InterpolatedString.cs index 752435122aa87..59cf5bace1423 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_InterpolatedString.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_InterpolatedString.cs @@ -99,7 +99,7 @@ private BoundExpression BindInterpolatedString(InterpolatedStringExpressionSynta if (interpolation.AlignmentClause != null) { alignment = GenerateConversionForAssignment(intType, BindValue(interpolation.AlignmentClause.Value, diagnostics, Binder.BindValueKind.RValue), diagnostics); - var alignmentConstant = alignment.ConstantValue; + var alignmentConstant = alignment.ConstantValueOpt; if (alignmentConstant != null && !alignmentConstant.IsBad) { const int magnitudeLimit = 32767; @@ -139,16 +139,16 @@ private BoundExpression BindInterpolatedString(InterpolatedStringExpressionSynta builder.Add(new BoundStringInsert(interpolation, value, alignment, format, isInterpolatedStringHandlerAppendCall: false)); if (!isResultConstant || - value.ConstantValue == null || + value.ConstantValueOpt == null || !(interpolation is { FormatClause: null, AlignmentClause: null }) || - !(value.ConstantValue is { IsString: true, IsBad: false })) + !(value.ConstantValueOpt is { IsString: true, IsBad: false })) { isResultConstant = false; continue; } resultConstant = (resultConstant is null) - ? value.ConstantValue - : FoldStringConcatenation(BinaryOperatorKind.StringConcatenation, resultConstant, value.ConstantValue); + ? value.ConstantValueOpt + : FoldStringConcatenation(BinaryOperatorKind.StringConcatenation, resultConstant, value.ConstantValueOpt); continue; } case SyntaxKind.InterpolatedStringText: @@ -237,7 +237,7 @@ private BoundInterpolatedString BindUnconvertedInterpolatedStringToString(BoundU // We need to do the determination of 1, 2, 3, or 4/5 up front, rather than in lowering, as it affects diagnostics (ref structs not being // able to be used, for example). However, between 4 and 5, we don't need to know at this point, so that logic is deferred for lowering. - if (unconvertedInterpolatedString.ConstantValue is not null) + if (unconvertedInterpolatedString.ConstantValueOpt is not null) { // Case 1 Debug.Assert(unconvertedInterpolatedString.Parts.All(static part => part.Type is null or { SpecialType: SpecialType.System_String })); @@ -265,7 +265,7 @@ BoundInterpolatedString constructWithData(ImmutableArray parts, unconvertedInterpolatedString.Syntax, data, parts, - unconvertedInterpolatedString.ConstantValue, + unconvertedInterpolatedString.ConstantValueOpt, unconvertedInterpolatedString.Type, unconvertedInterpolatedString.HasErrors); @@ -318,7 +318,7 @@ private bool TryBindUnconvertedBinaryOperatorToDefaultInterpolatedStringHandler( // The constant value is folded as part of creating the unconverted operator. If there is a constant value, then the top-level binary operator // will have one. - if (binaryOperator.ConstantValue is not null) + if (binaryOperator.ConstantValueOpt is not null) { // This is case 1. Let the standard machinery handle it return false; @@ -386,7 +386,7 @@ static BoundInterpolatedString createInterpolation(BoundUnconvertedInterpolatedS expression.Syntax, interpolationData: null, arg.AppendCalls[i], - expression.ConstantValue, + expression.ConstantValueOpt, expression.Type, expression.HasErrors); } @@ -397,7 +397,7 @@ static BoundBinaryOperator createBinaryOperator(BoundBinaryOperator original, Bo BinaryOperatorKind.StringConcatenation, left, right, - original.ConstantValue, + original.ConstantValueOpt, methodOpt: null, constrainedToTypeOpt: null, LookupResultKind.Viable, @@ -447,7 +447,7 @@ private BoundInterpolatedString BindUnconvertedInterpolatedStringToHandlerType( unconvertedInterpolatedString.Syntax, interpolationData, appendCalls[0], - unconvertedInterpolatedString.ConstantValue, + unconvertedInterpolatedString.ConstantValueOpt, unconvertedInterpolatedString.Type, unconvertedInterpolatedString.HasErrors); } @@ -575,7 +575,7 @@ private BoundBinaryOperator BindUnconvertedBinaryOperatorToInterpolatedStringHan // because we want to track that we're using the type no matter what. var boolType = GetSpecialType(SpecialType.System_Boolean, diagnostics, syntax); var trailingConstructorValidityPlaceholder = - new BoundInterpolatedStringArgumentPlaceholder(syntax, BoundInterpolatedStringArgumentPlaceholder.TrailingConstructorValidityParameter, valSafeToEscape: LocalScopeDepth, boolType) + new BoundInterpolatedStringArgumentPlaceholder(syntax, BoundInterpolatedStringArgumentPlaceholder.TrailingConstructorValidityParameter, boolType) { WasCompilerGenerated = true }; var outConstructorAdditionalArguments = additionalConstructorArguments.Add(trailingConstructorValidityPlaceholder); refKindsBuilder.Add(RefKind.Out); @@ -662,7 +662,6 @@ private BoundBinaryOperator BindUnconvertedBinaryOperatorToInterpolatedStringHan interpolatedStringHandlerType, constructorCall, usesBoolReturn, - LocalScopeDepth, additionalConstructorArguments.NullToEmpty(), positionInfo, implicitBuilderReceiver); @@ -782,8 +781,8 @@ private ImmutableArray BindInterpolatedStringParts(BoundUnconve else { var boundLiteral = (BoundLiteral)part; - Debug.Assert(boundLiteral.ConstantValue != null && boundLiteral.ConstantValue.IsString); - var literalText = boundLiteral.ConstantValue.StringValue; + Debug.Assert(boundLiteral.ConstantValueOpt != null && boundLiteral.ConstantValueOpt.IsString); + var literalText = boundLiteral.ConstantValueOpt.StringValue; methodName = BoundInterpolatedString.AppendLiteralMethod; argumentsBuilder.Add(boundLiteral.Update(ConstantValue.Create(literalText), boundLiteral.Type)); isLiteral = true; @@ -852,7 +851,6 @@ private BoundExpression BindInterpolatedStringHandlerInMemberCall( ref MemberAnalysisResult memberAnalysisResult, int interpolatedStringArgNum, BoundExpression? receiver, - bool requiresInstanceReceiver, BindingDiagnosticBag diagnostics) { Debug.Assert(unconvertedString is BoundUnconvertedInterpolatedString or BoundBinaryOperator { IsUnconvertedInterpolatedStringAddition: true }); @@ -1006,27 +1004,21 @@ private BoundExpression BindInterpolatedStringHandlerInMemberCall( } SyntaxNode placeholderSyntax; - uint valSafeToEscapeScope; bool isSuppressed; switch (argumentIndex) { case BoundInterpolatedStringArgumentPlaceholder.InstanceParameter: Debug.Assert(receiver != null); - valSafeToEscapeScope = requiresInstanceReceiver - ? receiver.GetRefKind().IsWritableReference() == true ? GetRefEscape(receiver, LocalScopeDepth) : GetValEscape(receiver, LocalScopeDepth) - : Binder.CallingMethodScope; isSuppressed = receiver.IsSuppressed; placeholderSyntax = receiver.Syntax; break; case BoundInterpolatedStringArgumentPlaceholder.UnspecifiedParameter: placeholderSyntax = unconvertedString.Syntax; - valSafeToEscapeScope = Binder.CallingMethodScope; isSuppressed = false; break; case >= 0: placeholderSyntax = arguments[argumentIndex].Syntax; - valSafeToEscapeScope = GetValEscape(arguments[argumentIndex], LocalScopeDepth); isSuppressed = arguments[argumentIndex].IsSuppressed; break; default: @@ -1037,7 +1029,6 @@ private BoundExpression BindInterpolatedStringHandlerInMemberCall( (BoundInterpolatedStringArgumentPlaceholder)(new BoundInterpolatedStringArgumentPlaceholder( placeholderSyntax, argumentIndex, - valSafeToEscapeScope, placeholderType, hasErrors: argumentIndex == BoundInterpolatedStringArgumentPlaceholder.UnspecifiedParameter) { WasCompilerGenerated = true }.WithSuppression(isSuppressed))); diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs index 48cd366f069b6..fea8c26e413d0 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs @@ -1126,20 +1126,6 @@ private BoundCall BindInvocationExpressionContinued( Debug.Assert(args.IsDefaultOrEmpty || (object)receiver != (object)args[0]); - if (!gotError) - { - CheckInvocationArgMixing( - node, - method, - receiver, - method.Parameters, - args, - argRefKinds, - argsToParams, - this.LocalScopeDepth, - diagnostics); - } - bool isDelegateCall = (object)delegateTypeOpt != null; if (!isDelegateCall) { @@ -2072,20 +2058,6 @@ private BoundFunctionPointerInvocation BindFunctionPointerInvocation(SyntaxNode var refKinds = analyzedArguments.RefKinds.ToImmutableOrNull(); bool hasErrors = ReportUnsafeIfNotAllowed(node, diagnostics); - if (!hasErrors) - { - hasErrors = !CheckInvocationArgMixing( - node, - funcPtr.Signature, - receiverOpt: null, - funcPtr.Signature.Parameters, - args, - refKinds, - methodResult.Result.ArgsToParamsOpt, - LocalScopeDepth, - diagnostics); - } - return new BoundFunctionPointerInvocation( node, boundExpression, diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Lambda.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Lambda.cs index b0929ad1f5955..5f818e6af0cb7 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Lambda.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Lambda.cs @@ -42,7 +42,7 @@ private UnboundLambda AnalyzeAnonymousFunction( ImmutableArray names = default; ImmutableArray refKinds = default; - ImmutableArray scopes = default; + ImmutableArray scopes = default; ImmutableArray types = default; ImmutableArray defaultValues = default; RefKind returnRefKind = RefKind.None; @@ -121,7 +121,7 @@ private UnboundLambda AnalyzeAnonymousFunction( var typesBuilder = ArrayBuilder.GetInstance(); var refKindsBuilder = ArrayBuilder.GetInstance(); - var scopesBuilder = ArrayBuilder.GetInstance(); + var scopesBuilder = ArrayBuilder.GetInstance(); var attributesBuilder = ArrayBuilder>.GetInstance(); var defaultValueBuilder = ArrayBuilder.GetInstance(); @@ -168,7 +168,7 @@ private UnboundLambda AnalyzeAnonymousFunction( var typeSyntax = p.Type; TypeWithAnnotations type = default; var refKind = RefKind.None; - var scope = DeclarationScope.Unscoped; + var scope = ScopedKind.None; if (typeSyntax == null) { @@ -214,7 +214,7 @@ private UnboundLambda AnalyzeAnonymousFunction( refKinds = refKindsBuilder.ToImmutable(); } - if (scopesBuilder.Any(s => s != DeclarationScope.Unscoped)) + if (scopesBuilder.Any(s => s != ScopedKind.None)) { scopes = scopesBuilder.ToImmutable(); } diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs index ea9ff23d68b10..983c8a82d4bdf 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs @@ -1771,8 +1771,8 @@ internal static SpecialType GetEnumPromotedType(SpecialType underlyingType) return nullableEqualityResult; } - var valueLeft = left.ConstantValue; - var valueRight = right.ConstantValue; + var valueLeft = left.ConstantValueOpt; + var valueRight = right.ConstantValueOpt; if (valueLeft == null || valueRight == null) { return null; @@ -1916,8 +1916,8 @@ internal static SpecialType GetEnumPromotedType(SpecialType underlyingType) { BoundConversion leftConv = (BoundConversion)left; BoundConversion rightConv = (BoundConversion)right; - ConstantValue? leftConstant = leftConv.Operand.ConstantValue; - ConstantValue? rightConstant = rightConv.Operand.ConstantValue; + ConstantValue? leftConstant = leftConv.Operand.ConstantValueOpt; + ConstantValue? rightConstant = rightConv.Operand.ConstantValueOpt; if (leftConstant != null && rightConstant != null) { @@ -2796,7 +2796,7 @@ private BoundExpression BindUnaryOperatorCore(CSharpSyntaxNode node, string oper return null; } - var value = operand.ConstantValue; + var value = operand.ConstantValueOpt; if (value == null || value.IsBad) { return value; @@ -3227,7 +3227,7 @@ private BoundExpression BindIsOperator(BinaryExpressionSyntax node, BindingDiagn CompoundUseSiteInfo useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics); - if (operand.ConstantValue == ConstantValue.Null || + if (operand.ConstantValueOpt == ConstantValue.Null || operand.Kind == BoundKind.MethodGroup || operand.Type.IsVoidType()) { @@ -3269,7 +3269,7 @@ private BoundExpression BindIsOperator(BinaryExpressionSyntax node, BindingDiagn Conversion conversion = Conversions.ClassifyBuiltInConversion(operandType, targetType, isChecked: CheckOverflowAtRuntime, ref useSiteInfo); diagnostics.Add(node, useSiteInfo); - ReportIsOperatorDiagnostics(node, diagnostics, operandType, targetType, conversion.Kind, operand.ConstantValue); + ReportIsOperatorDiagnostics(node, diagnostics, operandType, targetType, conversion.Kind, operand.ConstantValueOpt); return new BoundIsOperator(node, operand, typeExpression, conversion.Kind, resultType); bool tryBindAsType( @@ -3736,7 +3736,7 @@ private BoundExpression BindAsOperator(BinaryExpressionSyntax node, BindingDiagn CompoundUseSiteInfo useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics); Conversion conversion = Conversions.ClassifyBuiltInConversion(operandType, targetType, isChecked: CheckOverflowAtRuntime, ref useSiteInfo); diagnostics.Add(node, useSiteInfo); - bool hasErrors = ReportAsOperatorConversionDiagnostics(node, diagnostics, this.Compilation, operandType, targetType, conversion.Kind, operand.ConstantValue); + bool hasErrors = ReportAsOperatorConversionDiagnostics(node, diagnostics, this.Compilation, operandType, targetType, conversion.Kind, operand.ConstantValueOpt); if (conversion.Exists) { @@ -4277,50 +4277,55 @@ private BoundExpression BindRefConditionalOperator(ConditionalExpressionSyntax n Debug.Assert(Conversions.HasIdentityConversion(falseType, type)); } - if (!hasErrors) - { - var currentScope = this.LocalScopeDepth; + trueExpr = BindToNaturalType(trueExpr, diagnostics, reportNoTargetType: false); + falseExpr = BindToNaturalType(falseExpr, diagnostics, reportNoTargetType: false); + return new BoundConditionalOperator(node, isRef: true, condition, trueExpr, falseExpr, constantValueOpt: null, type, wasTargetTyped: false, type, hasErrors); + } + } - // val-escape must agree on both branches. - uint whenTrueEscape = GetValEscape(trueExpr, currentScope); - uint whenFalseEscape = GetValEscape(falseExpr, currentScope); + partial class RefSafetyAnalysis + { + private void ValidateRefConditionalOperator(SyntaxNode node, BoundExpression trueExpr, BoundExpression falseExpr, BindingDiagnosticBag diagnostics) + { + var currentScope = _localScopeDepth; - if (whenTrueEscape != whenFalseEscape) - { - // ask the one with narrower escape, for the wider - hopefully the errors will make the violation easier to fix. - if (whenTrueEscape < whenFalseEscape) - CheckValEscape(falseExpr.Syntax, falseExpr, currentScope, whenTrueEscape, checkingReceiver: false, diagnostics: diagnostics); - else - CheckValEscape(trueExpr.Syntax, trueExpr, currentScope, whenFalseEscape, checkingReceiver: false, diagnostics: diagnostics); + // val-escape must agree on both branches. + uint whenTrueEscape = GetValEscape(trueExpr, currentScope); + uint whenFalseEscape = GetValEscape(falseExpr, currentScope); - diagnostics.Add(this.InUnsafeRegion ? ErrorCode.WRN_MismatchedRefEscapeInTernary : ErrorCode.ERR_MismatchedRefEscapeInTernary, node.Location); - hasErrors = !this.InUnsafeRegion; - } - } + if (whenTrueEscape != whenFalseEscape) + { + // ask the one with narrower escape, for the wider - hopefully the errors will make the violation easier to fix. + if (whenTrueEscape < whenFalseEscape) + CheckValEscape(falseExpr.Syntax, falseExpr, currentScope, whenTrueEscape, checkingReceiver: false, diagnostics: diagnostics); + else + CheckValEscape(trueExpr.Syntax, trueExpr, currentScope, whenFalseEscape, checkingReceiver: false, diagnostics: diagnostics); - trueExpr = BindToNaturalType(trueExpr, diagnostics, reportNoTargetType: false); - falseExpr = BindToNaturalType(falseExpr, diagnostics, reportNoTargetType: false); - return new BoundConditionalOperator(node, isRef: true, condition, trueExpr, falseExpr, constantValueOpt: null, type, wasTargetTyped: false, type, hasErrors); + diagnostics.Add(_inUnsafeRegion ? ErrorCode.WRN_MismatchedRefEscapeInTernary : ErrorCode.ERR_MismatchedRefEscapeInTernary, node.Location); + } } + } + partial class Binder + { /// /// Constant folding for conditional (aka ternary) operators. /// private static ConstantValue FoldConditionalOperator(BoundExpression condition, BoundExpression trueExpr, BoundExpression falseExpr) { - ConstantValue trueValue = trueExpr.ConstantValue; + ConstantValue trueValue = trueExpr.ConstantValueOpt; if (trueValue == null || trueValue.IsBad) { return trueValue; } - ConstantValue falseValue = falseExpr.ConstantValue; + ConstantValue falseValue = falseExpr.ConstantValueOpt; if (falseValue == null || falseValue.IsBad) { return falseValue; } - ConstantValue conditionValue = condition.ConstantValue; + ConstantValue conditionValue = condition.ConstantValueOpt; if (conditionValue == null || conditionValue.IsBad) { return conditionValue; diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs index 03f630b52dae4..749c82ff1cf8a 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs @@ -35,8 +35,7 @@ private BoundExpression BindIsPatternExpression(IsPatternExpressionSyntax node, } Debug.Assert(expression.Type is { }); - uint inputValEscape = GetValEscape(expression, LocalScopeDepth); - BoundPattern pattern = BindPattern(node.Pattern, expression.Type, inputValEscape, permitDesignations: true, hasErrors, diagnostics, underIsPattern: true); + BoundPattern pattern = BindPattern(node.Pattern, expression.Type, permitDesignations: true, hasErrors, diagnostics, underIsPattern: true); hasErrors |= pattern.HasErrors; return MakeIsPatternExpression( node, expression, pattern, GetSpecialType(SpecialType.System_Boolean, diagnostics, node), @@ -94,7 +93,7 @@ private BoundExpression MakeIsPatternExpression( } } } - else if (expression.ConstantValue != null) + else if (expression.ConstantValueOpt != null) { decisionDag = decisionDag.SimplifyDecisionDagIfConstantInput(expression); if (!hasErrors && getConstantResult(decisionDag, negated, whenTrueLabel, whenFalseLabel) is { } simplifiedResult) @@ -164,7 +163,6 @@ internal virtual BoundExpression BindSwitchExpressionCore( internal BoundPattern BindPattern( PatternSyntax node, TypeSymbol inputType, - uint inputValEscape, bool permitDesignations, bool hasErrors, BindingDiagnosticBag diagnostics, @@ -173,17 +171,17 @@ internal BoundPattern BindPattern( return node switch { DiscardPatternSyntax p => BindDiscardPattern(p, inputType, diagnostics), - DeclarationPatternSyntax p => BindDeclarationPattern(p, inputType, inputValEscape, permitDesignations, hasErrors, diagnostics), + DeclarationPatternSyntax p => BindDeclarationPattern(p, inputType, permitDesignations, hasErrors, diagnostics), ConstantPatternSyntax p => BindConstantPatternWithFallbackToTypePattern(p, inputType, hasErrors, diagnostics), - RecursivePatternSyntax p => BindRecursivePattern(p, inputType, inputValEscape, permitDesignations, hasErrors, diagnostics), - VarPatternSyntax p => BindVarPattern(p, inputType, inputValEscape, permitDesignations, hasErrors, diagnostics), - ParenthesizedPatternSyntax p => BindParenthesizedPattern(p, inputType, inputValEscape, permitDesignations, hasErrors, diagnostics, underIsPattern), - BinaryPatternSyntax p => BindBinaryPattern(p, inputType, inputValEscape, permitDesignations, hasErrors, diagnostics), - UnaryPatternSyntax p => BindUnaryPattern(p, inputType, inputValEscape, hasErrors, diagnostics, underIsPattern), + RecursivePatternSyntax p => BindRecursivePattern(p, inputType, permitDesignations, hasErrors, diagnostics), + VarPatternSyntax p => BindVarPattern(p, inputType, permitDesignations, hasErrors, diagnostics), + ParenthesizedPatternSyntax p => BindParenthesizedPattern(p, inputType, permitDesignations, hasErrors, diagnostics, underIsPattern), + BinaryPatternSyntax p => BindBinaryPattern(p, inputType, permitDesignations, hasErrors, diagnostics), + UnaryPatternSyntax p => BindUnaryPattern(p, inputType, hasErrors, diagnostics, underIsPattern), RelationalPatternSyntax p => BindRelationalPattern(p, inputType, hasErrors, diagnostics), TypePatternSyntax p => BindTypePattern(p, inputType, hasErrors, diagnostics), - ListPatternSyntax p => BindListPattern(p, inputType, inputValEscape, permitDesignations, hasErrors, diagnostics), - SlicePatternSyntax p => BindSlicePattern(p, inputType, inputValEscape, permitDesignations, ref hasErrors, misplaced: true, diagnostics), + ListPatternSyntax p => BindListPattern(p, inputType, permitDesignations, hasErrors, diagnostics), + SlicePatternSyntax p => BindSlicePattern(p, inputType, permitDesignations, ref hasErrors, misplaced: true, diagnostics), _ => throw ExceptionUtilities.UnexpectedValue(node.Kind()), }; } @@ -191,20 +189,18 @@ internal BoundPattern BindPattern( private BoundPattern BindParenthesizedPattern( ParenthesizedPatternSyntax node, TypeSymbol inputType, - uint inputValEscape, bool permitDesignations, bool hasErrors, BindingDiagnosticBag diagnostics, bool underIsPattern) { MessageID.IDS_FeatureParenthesizedPattern.CheckFeatureAvailability(diagnostics, node, node.OpenParenToken.GetLocation()); - return BindPattern(node.Pattern, inputType, inputValEscape, permitDesignations, hasErrors, diagnostics, underIsPattern); + return BindPattern(node.Pattern, inputType, permitDesignations, hasErrors, diagnostics, underIsPattern); } private BoundPattern BindSlicePattern( SlicePatternSyntax node, TypeSymbol inputType, - uint inputValEscape, bool permitDesignations, ref bool hasErrors, bool misplaced, @@ -224,7 +220,7 @@ private BoundPattern BindSlicePattern( // We don't require the type to be sliceable if there's no subpattern. if (node.Pattern is not null) { - receiverPlaceholder = new BoundSlicePatternReceiverPlaceholder(node, GetValEscape(inputType, inputValEscape), inputType) { WasCompilerGenerated = true }; + receiverPlaceholder = new BoundSlicePatternReceiverPlaceholder(node, inputType) { WasCompilerGenerated = true }; var systemRangeType = GetWellKnownType(WellKnownType.System_Range, diagnostics, node); argumentPlaceholder = new BoundSlicePatternRangePlaceholder(node, systemRangeType) { WasCompilerGenerated = true }; @@ -253,7 +249,7 @@ private BoundPattern BindSlicePattern( sliceType = indexerAccess.Type; } - pattern = BindPattern(node.Pattern, sliceType, GetValEscape(sliceType, inputValEscape), permitDesignations, hasErrors, diagnostics); + pattern = BindPattern(node.Pattern, sliceType, permitDesignations, hasErrors, diagnostics); } return new BoundSlicePattern(node, pattern, indexerAccess, receiverPlaceholder, argumentPlaceholder, inputType: inputType, narrowedType: inputType, hasErrors); @@ -262,7 +258,6 @@ private BoundPattern BindSlicePattern( private ImmutableArray BindListPatternSubpatterns( SeparatedSyntaxList subpatterns, TypeSymbol inputType, - uint inputValEscape, TypeSymbol elementType, bool permitDesignations, ref bool hasErrors, @@ -276,12 +271,12 @@ private ImmutableArray BindListPatternSubpatterns( BoundPattern boundPattern; if (pattern is SlicePatternSyntax slice) { - boundPattern = BindSlicePattern(slice, inputType, GetValEscape(inputType, inputValEscape), permitDesignations, ref hasErrors, misplaced: sawSlice, diagnostics: diagnostics); + boundPattern = BindSlicePattern(slice, inputType, permitDesignations, ref hasErrors, misplaced: sawSlice, diagnostics: diagnostics); sawSlice = true; } else { - boundPattern = BindPattern(pattern, elementType, GetValEscape(elementType, inputValEscape), permitDesignations, hasErrors, diagnostics); + boundPattern = BindPattern(pattern, elementType, permitDesignations, hasErrors, diagnostics); } builder.Add(boundPattern); @@ -293,7 +288,6 @@ private ImmutableArray BindListPatternSubpatterns( private BoundListPattern BindListPattern( ListPatternSyntax node, TypeSymbol inputType, - uint inputValEscape, bool permitDesignations, bool hasErrors, BindingDiagnosticBag diagnostics) @@ -323,20 +317,20 @@ private BoundListPattern BindListPattern( } else { - hasErrors |= !BindLengthAndIndexerForListPattern(node, narrowedType, inputValEscape, diagnostics, out indexerAccess, out lengthAccess, out receiverPlaceholder, out argumentPlaceholder); + hasErrors |= !BindLengthAndIndexerForListPattern(node, narrowedType, diagnostics, out indexerAccess, out lengthAccess, out receiverPlaceholder, out argumentPlaceholder); Debug.Assert(indexerAccess!.Type is not null); elementType = indexerAccess.Type; } ImmutableArray subpatterns = BindListPatternSubpatterns( - node.Patterns, inputType: narrowedType, inputValEscape, elementType: elementType, + node.Patterns, inputType: narrowedType, elementType: elementType, permitDesignations, ref hasErrors, out bool sawSlice, diagnostics); BindPatternDesignation( node.Designation, declType: TypeWithAnnotations.Create(narrowedType, NullableAnnotation.NotAnnotated), - inputValEscape, permitDesignations, typeSyntax: null, diagnostics, ref hasErrors, + permitDesignations, typeSyntax: null, diagnostics, ref hasErrors, out Symbol? variableSymbol, out BoundExpression? variableAccess); return new BoundListPattern( @@ -351,19 +345,19 @@ private BoundListPattern BindListPattern( /// private bool IsCountableAndIndexable(SyntaxNode node, TypeSymbol inputType, out PropertySymbol? lengthProperty) { - var success = BindLengthAndIndexerForListPattern(node, inputType, inputValEscape: CallingMethodScope, BindingDiagnosticBag.Discarded, + var success = BindLengthAndIndexerForListPattern(node, inputType, BindingDiagnosticBag.Discarded, indexerAccess: out _, out var lengthAccess, receiverPlaceholder: out _, argumentPlaceholder: out _); lengthProperty = success ? GetPropertySymbol(lengthAccess, out _, out _) : null; return success; } - private bool BindLengthAndIndexerForListPattern(SyntaxNode node, TypeSymbol inputType, uint inputValEscape, BindingDiagnosticBag diagnostics, + private bool BindLengthAndIndexerForListPattern(SyntaxNode node, TypeSymbol inputType, BindingDiagnosticBag diagnostics, out BoundExpression indexerAccess, out BoundExpression lengthAccess, out BoundListPatternReceiverPlaceholder? receiverPlaceholder, out BoundListPatternIndexPlaceholder argumentPlaceholder) { Debug.Assert(!inputType.IsDynamic()); bool hasErrors = false; - receiverPlaceholder = new BoundListPatternReceiverPlaceholder(node, GetValEscape(inputType, inputValEscape), inputType) { WasCompilerGenerated = true }; + receiverPlaceholder = new BoundListPatternReceiverPlaceholder(node, inputType) { WasCompilerGenerated = true }; if (inputType.IsSZArray()) { hasErrors |= !TryGetSpecialTypeMember(Compilation, SpecialMember.System_Array__Length, node, diagnostics, out PropertySymbol lengthProperty); @@ -598,10 +592,10 @@ internal BoundExpression ConvertPatternExpression( { convertedExpression = expression; // If the expression does not have a constant value, an error will be reported in the caller - if (!hasErrors && expression.ConstantValue is object) + if (!hasErrors && expression.ConstantValueOpt is object) { CompoundUseSiteInfo useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics); - if (expression.ConstantValue == ConstantValue.Null) + if (expression.ConstantValueOpt == ConstantValue.Null) { // Pointers are value types, but they can be assigned null, so they can be matched against null. if (inputType.IsNonNullableValueType() && !inputType.IsPointerOrFunctionPointer()) @@ -664,7 +658,7 @@ internal BoundExpression ConvertPatternExpression( convertedExpression = BindToNaturalType(expression, diagnostics); - constantValue = convertedExpression.ConstantValue; + constantValue = convertedExpression.ConstantValueOpt; if (constantValue == ConstantValue.Null) { diagnostics.Add(ErrorCode.ERR_PatternSpanCharCannotBeStringNull, convertedExpression.Syntax.Location, inputType); @@ -684,14 +678,14 @@ internal BoundExpression ConvertPatternExpression( { var conversion = (BoundConversion)convertedExpression; BoundExpression operand = conversion.Operand; - if (inputType.IsNullableType() && (convertedExpression.ConstantValue == null || !convertedExpression.ConstantValue.IsNull)) + if (inputType.IsNullableType() && (convertedExpression.ConstantValueOpt == null || !convertedExpression.ConstantValueOpt.IsNull)) { // Null is a special case here because we want to compare null to the Nullable itself, not to the underlying type. // We are not interested in the diagnostic that get created here convertedExpression = CreateConversion(operand, inputType.GetNullableUnderlyingType(), BindingDiagnosticBag.Discarded); } else if ((conversion.ConversionKind == ConversionKind.Boxing || conversion.ConversionKind == ConversionKind.ImplicitReference) - && operand.ConstantValue != null && convertedExpression.ConstantValue == null) + && operand.ConstantValueOpt != null && convertedExpression.ConstantValueOpt == null) { // A boxed constant (or string converted to object) is a special case because we prefer // to compare to the pre-converted value by casting the input value to the type of the constant @@ -708,7 +702,7 @@ internal BoundExpression ConvertPatternExpression( } } - constantValue = convertedExpression.ConstantValue; + constantValue = convertedExpression.ConstantValueOpt; return convertedExpression; } @@ -833,16 +827,14 @@ internal static ConstantValue ExpressionOfTypeMatchesPatternType( private BoundPattern BindDeclarationPattern( DeclarationPatternSyntax node, TypeSymbol inputType, - uint inputValEscape, bool permitDesignations, bool hasErrors, BindingDiagnosticBag diagnostics) { TypeSyntax typeSyntax = node.Type; BoundTypeExpression boundDeclType = BindTypeForPattern(typeSyntax, inputType, diagnostics, ref hasErrors); - var valEscape = GetValEscape(boundDeclType.Type, inputValEscape); BindPatternDesignation( - designation: node.Designation, declType: boundDeclType.TypeWithAnnotations, valEscape, permitDesignations, typeSyntax, diagnostics, + designation: node.Designation, declType: boundDeclType.TypeWithAnnotations, permitDesignations, typeSyntax, diagnostics, hasErrors: ref hasErrors, variableSymbol: out Symbol? variableSymbol, variableAccess: out BoundExpression? variableAccess); return new BoundDeclarationPattern(node, boundDeclType, isVar: false, variableSymbol, variableAccess, inputType: inputType, narrowedType: boundDeclType.Type, hasErrors); } @@ -864,7 +856,6 @@ private BoundTypeExpression BindTypeForPattern( private void BindPatternDesignation( VariableDesignationSyntax? designation, TypeWithAnnotations declType, - uint inputValEscape, bool permitDesignations, TypeSyntax? typeSyntax, BindingDiagnosticBag diagnostics, @@ -888,7 +879,6 @@ private void BindPatternDesignation( CheckFeatureAvailability(designation, MessageID.IDS_FeatureExpressionVariablesInQueriesAndInitializers, diagnostics); localSymbol.SetTypeWithAnnotations(declType); - localSymbol.SetValEscape(GetValEscape(declType.Type, inputValEscape)); // Check for variable declaration errors. hasErrors |= localSymbol.ScopeBinder.ValidateDeclarationNameConflictsInScope(localSymbol, diagnostics); @@ -924,16 +914,6 @@ private void BindPatternDesignation( } } - /// - /// Compute the val escape of an expression of the given , which is known to be derived - /// from an expression whose escape scope is . By the language rules, the - /// result is either that same scope (if the type is a ref struct type) or . - /// - private static uint GetValEscape(TypeSymbol type, uint possibleValEscape) - { - return type.IsRefLikeType ? possibleValEscape : Binder.CallingMethodScope; - } - private TypeWithAnnotations BindRecursivePatternType( TypeSyntax? typeSyntax, TypeSymbol inputType, @@ -967,7 +947,6 @@ internal static bool IsZeroElementTupleType(TypeSymbol type) private BoundPattern BindRecursivePattern( RecursivePatternSyntax node, TypeSymbol inputType, - uint inputValEscape, bool permitDesignations, bool hasErrors, BindingDiagnosticBag diagnostics) @@ -984,7 +963,6 @@ private BoundPattern BindRecursivePattern( TypeSyntax? typeSyntax = node.Type; TypeWithAnnotations declTypeWithAnnotations = BindRecursivePatternType(typeSyntax, inputType, diagnostics, ref hasErrors, out BoundTypeExpression? boundDeclType); TypeSymbol declType = declTypeWithAnnotations.Type; - inputValEscape = GetValEscape(declType, inputValEscape); MethodSymbol? deconstructMethod = null; ImmutableArray deconstructionSubpatterns = default; @@ -998,12 +976,12 @@ private BoundPattern BindRecursivePattern( // do not correctly treat the non-generic struct `System.ValueTuple` as a tuple type. We explicitly perform the tests // required to identify it. When that bug is fixed we should be able to remove this if statement. BindValueTupleSubpatterns( - positionalClause, declType, ImmutableArray.Empty, inputValEscape, permitDesignations, ref hasErrors, patternsBuilder, diagnostics); + positionalClause, declType, ImmutableArray.Empty, permitDesignations, ref hasErrors, patternsBuilder, diagnostics); } else if (declType.IsTupleType) { // It is a tuple type. Work according to its elements - BindValueTupleSubpatterns(positionalClause, declType, declType.TupleElementTypesWithAnnotations, inputValEscape, permitDesignations, ref hasErrors, patternsBuilder, diagnostics); + BindValueTupleSubpatterns(positionalClause, declType, declType.TupleElementTypesWithAnnotations, permitDesignations, ref hasErrors, patternsBuilder, diagnostics); } else { @@ -1030,7 +1008,7 @@ private BoundPattern BindRecursivePattern( } deconstructMethod = BindDeconstructSubpatterns( - positionalClause, inputValEscape, permitDesignations, deconstruct, outPlaceholders, patternsBuilder, ref hasErrors, diagnostics); + positionalClause, permitDesignations, deconstruct, outPlaceholders, patternsBuilder, ref hasErrors, diagnostics); } deconstructionSubpatterns = patternsBuilder.ToImmutableAndFree(); @@ -1039,11 +1017,11 @@ private BoundPattern BindRecursivePattern( ImmutableArray properties = default; if (node.PropertyPatternClause != null) { - properties = BindPropertyPatternClause(node.PropertyPatternClause, declType, inputValEscape, permitDesignations, diagnostics, ref hasErrors); + properties = BindPropertyPatternClause(node.PropertyPatternClause, declType, permitDesignations, diagnostics, ref hasErrors); } BindPatternDesignation( - node.Designation, declTypeWithAnnotations, inputValEscape, permitDesignations, typeSyntax, diagnostics, + node.Designation, declTypeWithAnnotations, permitDesignations, typeSyntax, diagnostics, ref hasErrors, out Symbol? variableSymbol, out BoundExpression? variableAccess); bool isExplicitNotNullTest = node.Designation is null && @@ -1060,7 +1038,6 @@ deconstructMethod is null && private MethodSymbol? BindDeconstructSubpatterns( PositionalPatternClauseSyntax node, - uint inputValEscape, bool permitDesignations, BoundExpression deconstruct, ImmutableArray outPlaceholders, @@ -1082,13 +1059,16 @@ deconstructMethod is null && ParameterSymbol? parameter = null; if (!isError) { + int parameterIndex = i + skippedExtensionParameters; + if (parameterIndex < deconstructMethod!.ParameterCount) + { + parameter = deconstructMethod.Parameters[parameterIndex]; + } if (subPattern.NameColon != null) { // Check that the given name is the same as the corresponding parameter of the method. - int parameterIndex = i + skippedExtensionParameters; - if (parameterIndex < deconstructMethod!.ParameterCount) + if (parameter is { }) { - parameter = deconstructMethod.Parameters[parameterIndex]; string name = subPattern.NameColon.Name.Identifier.ValueText; string parameterName = parameter.Name; if (name != parameterName) @@ -1108,7 +1088,7 @@ deconstructMethod is null && var boundSubpattern = new BoundPositionalSubpattern( subPattern, parameter, - BindPattern(subPattern.Pattern, elementType, GetValEscape(elementType, inputValEscape), permitDesignations, isError, diagnostics) + BindPattern(subPattern.Pattern, elementType, permitDesignations, isError, diagnostics) ); patterns.Add(boundSubpattern); } @@ -1122,8 +1102,6 @@ private void BindITupleSubpatterns( bool permitDesignations, BindingDiagnosticBag diagnostics) { - // Since the input has been cast to ITuple, it must be escapable. - const uint valEscape = Binder.CallingMethodScope; var objectType = Compilation.GetSpecialType(SpecialType.System_Object); foreach (var subpatternSyntax in node.Subpatterns) { @@ -1140,7 +1118,7 @@ private void BindITupleSubpatterns( var boundSubpattern = new BoundPositionalSubpattern( subpatternSyntax, null, - BindPattern(subpatternSyntax.Pattern, objectType, valEscape, permitDesignations, hasErrors: false, diagnostics)); + BindPattern(subpatternSyntax.Pattern, objectType, permitDesignations, hasErrors: false, diagnostics)); patterns.Add(boundSubpattern); } } @@ -1151,12 +1129,10 @@ private void BindITupleSubpatterns( bool permitDesignations, BindingDiagnosticBag diagnostics) { - // Since the input has been cast to ITuple, it must be escapable. - const uint valEscape = Binder.CallingMethodScope; var objectType = Compilation.GetSpecialType(SpecialType.System_Object); foreach (var variable in node.Variables) { - BoundPattern pattern = BindVarDesignation(variable, objectType, valEscape, permitDesignations, hasErrors: false, diagnostics); + BoundPattern pattern = BindVarDesignation(variable, objectType, permitDesignations, hasErrors: false, diagnostics); var boundSubpattern = new BoundPositionalSubpattern( variable, null, @@ -1169,7 +1145,6 @@ private void BindValueTupleSubpatterns( PositionalPatternClauseSyntax node, TypeSymbol declType, ImmutableArray elementTypesWithAnnotations, - uint inputValEscape, bool permitDesignations, ref bool hasErrors, ArrayBuilder patterns, @@ -1203,7 +1178,7 @@ private void BindValueTupleSubpatterns( BoundPositionalSubpattern boundSubpattern = new BoundPositionalSubpattern( subpatternSyntax, foundField, - BindPattern(subpatternSyntax.Pattern, elementType, GetValEscape(elementType, inputValEscape), permitDesignations, isError, diagnostics)); + BindPattern(subpatternSyntax.Pattern, elementType, permitDesignations, isError, diagnostics)); patterns.Add(boundSubpattern); } } @@ -1332,7 +1307,6 @@ bool hasBaseInterface(TypeSymbol type, NamedTypeSymbol possibleBaseInterface) private BoundPattern BindVarPattern( VarPatternSyntax node, TypeSymbol inputType, - uint inputValEscape, bool permitDesignations, bool hasErrors, BindingDiagnosticBag diagnostics) @@ -1353,13 +1327,12 @@ private BoundPattern BindVarPattern( hasErrors = true; } - return BindVarDesignation(node.Designation, inputType, inputValEscape, permitDesignations, hasErrors, diagnostics); + return BindVarDesignation(node.Designation, inputType, permitDesignations, hasErrors, diagnostics); } private BoundPattern BindVarDesignation( VariableDesignationSyntax node, TypeSymbol inputType, - uint inputValEscape, bool permitDesignations, bool hasErrors, BindingDiagnosticBag diagnostics) @@ -1374,7 +1347,7 @@ private BoundPattern BindVarDesignation( { var declType = TypeWithState.ForType(inputType).ToTypeWithAnnotations(Compilation); BindPatternDesignation( - designation: node, declType: declType, inputValEscape: inputValEscape, permitDesignations: permitDesignations, + designation: node, declType: declType, permitDesignations: permitDesignations, typeSyntax: null, diagnostics: diagnostics, hasErrors: ref hasErrors, variableSymbol: out Symbol? variableSymbol, variableAccess: out BoundExpression? variableAccess); var boundOperandType = new BoundTypeExpression(syntax: node, aliasOpt: null, typeWithAnnotations: declType); // fake a type expression for the variable's type @@ -1438,7 +1411,7 @@ private BoundPattern BindVarDesignation( var variable = tupleDesignation.Variables[i]; bool isError = outPlaceholders.IsDefaultOrEmpty || i >= outPlaceholders.Length; TypeSymbol elementType = isError ? CreateErrorType() : outPlaceholders[i].Type; - BoundPattern pattern = BindVarDesignation(variable, elementType, GetValEscape(elementType, inputValEscape), permitDesignations, isError, diagnostics); + BoundPattern pattern = BindVarDesignation(variable, elementType, permitDesignations, isError, diagnostics); subPatterns.Add(new BoundPositionalSubpattern(variable, symbol: null, pattern)); } } @@ -1461,7 +1434,7 @@ void addSubpatternsForTuple(ImmutableArray elementTypes) var variable = tupleDesignation.Variables[i]; bool isError = i >= elementTypes.Length; TypeSymbol elementType = isError ? CreateErrorType() : elementTypes[i].Type; - BoundPattern pattern = BindVarDesignation(variable, elementType, GetValEscape(elementType, inputValEscape), permitDesignations, isError, diagnostics); + BoundPattern pattern = BindVarDesignation(variable, elementType, permitDesignations, isError, diagnostics); subPatterns.Add(new BoundPositionalSubpattern(variable, symbol: null, pattern)); } } @@ -1476,7 +1449,6 @@ void addSubpatternsForTuple(ImmutableArray elementTypes) private ImmutableArray BindPropertyPatternClause( PropertyPatternClauseSyntax node, TypeSymbol inputType, - uint inputValEscape, bool permitDesignations, BindingDiagnosticBag diagnostics, ref bool hasErrors) @@ -1503,7 +1475,7 @@ private ImmutableArray BindPropertyPatternClause( } else { - member = LookupMembersForPropertyPattern(inputType, expr, diagnostics, ref inputValEscape, ref hasErrors); + member = LookupMembersForPropertyPattern(inputType, expr, diagnostics, ref hasErrors); memberType = member.Type; // If we're dealing with the member that makes the type countable, and the type is also indexable, then it will be assumed to always return a non-negative value if (memberType.SpecialType == SpecialType.System_Int32 && @@ -1518,7 +1490,7 @@ private ImmutableArray BindPropertyPatternClause( } } - BoundPattern boundPattern = BindPattern(pattern, memberType, inputValEscape, permitDesignations, hasErrors, diagnostics); + BoundPattern boundPattern = BindPattern(pattern, memberType, permitDesignations, hasErrors, diagnostics); builder.Add(new BoundPropertySubpattern(p, member, isLengthOrCount, boundPattern)); } @@ -1526,7 +1498,7 @@ private ImmutableArray BindPropertyPatternClause( } private BoundPropertySubpatternMember LookupMembersForPropertyPattern( - TypeSymbol inputType, ExpressionSyntax expr, BindingDiagnosticBag diagnostics, ref uint inputValEscape, ref bool hasErrors) + TypeSymbol inputType, ExpressionSyntax expr, BindingDiagnosticBag diagnostics, ref bool hasErrors) { BoundPropertySubpatternMember? receiver = null; Symbol? symbol = null; @@ -1536,7 +1508,7 @@ private BoundPropertySubpatternMember LookupMembersForPropertyPattern( symbol = BindPropertyPatternMember(inputType, name, ref hasErrors, diagnostics); break; case MemberAccessExpressionSyntax { Name: IdentifierNameSyntax name } memberAccess when memberAccess.IsKind(SyntaxKind.SimpleMemberAccessExpression): - receiver = LookupMembersForPropertyPattern(inputType, memberAccess.Expression, diagnostics, ref inputValEscape, ref hasErrors); + receiver = LookupMembersForPropertyPattern(inputType, memberAccess.Expression, diagnostics, ref hasErrors); symbol = BindPropertyPatternMember(receiver.Type.StrippedType(), name, ref hasErrors, diagnostics); break; default: @@ -1552,8 +1524,6 @@ private BoundPropertySubpatternMember LookupMembersForPropertyPattern( _ => CreateErrorType() }; - // Note: since we're recursing on the receiver, the val escape correctly flows from inside out. - inputValEscape = GetValEscape(memberType, inputValEscape); return new BoundPropertySubpatternMember(expr, receiver, symbol, type: memberType, hasErrors); } @@ -1736,7 +1706,6 @@ private BoundPattern BindRelationalPattern( private BoundPattern BindUnaryPattern( UnaryPatternSyntax node, TypeSymbol inputType, - uint inputValEscape, bool hasErrors, BindingDiagnosticBag diagnostics, bool underIsPattern) @@ -1744,14 +1713,13 @@ private BoundPattern BindUnaryPattern( MessageID.IDS_FeatureNotPattern.CheckFeatureAvailability(diagnostics, node, node.OperatorToken.GetLocation()); bool permitDesignations = underIsPattern; // prevent designators under 'not' except under an is-pattern - var subPattern = BindPattern(node.Pattern, inputType, inputValEscape, permitDesignations, hasErrors, diagnostics, underIsPattern); + var subPattern = BindPattern(node.Pattern, inputType, permitDesignations, hasErrors, diagnostics, underIsPattern); return new BoundNegatedPattern(node, subPattern, inputType: inputType, narrowedType: inputType, hasErrors); } private BoundPattern BindBinaryPattern( BinaryPatternSyntax node, TypeSymbol inputType, - uint inputValEscape, bool permitDesignations, bool hasErrors, BindingDiagnosticBag diagnostics) @@ -1762,8 +1730,8 @@ private BoundPattern BindBinaryPattern( MessageID.IDS_FeatureOrPattern.CheckFeatureAvailability(diagnostics, node, node.OperatorToken.GetLocation()); permitDesignations = false; // prevent designators under 'or' - var left = BindPattern(node.Left, inputType, inputValEscape, permitDesignations, hasErrors, diagnostics); - var right = BindPattern(node.Right, inputType, inputValEscape, permitDesignations, hasErrors, diagnostics); + var left = BindPattern(node.Left, inputType, permitDesignations, hasErrors, diagnostics); + var right = BindPattern(node.Right, inputType, permitDesignations, hasErrors, diagnostics); // Compute the common type. This algorithm is quadratic, but disjunctive patterns are unlikely to be huge var narrowedTypeCandidates = ArrayBuilder.GetInstance(2); @@ -1846,9 +1814,8 @@ static void collectCandidates(BoundPattern pat, ArrayBuilder candida { MessageID.IDS_FeatureAndPattern.CheckFeatureAvailability(diagnostics, node, node.OperatorToken.GetLocation()); - var left = BindPattern(node.Left, inputType, inputValEscape, permitDesignations, hasErrors, diagnostics); - var leftOutputValEscape = GetValEscape(left.NarrowedType, inputValEscape); - var right = BindPattern(node.Right, left.NarrowedType, leftOutputValEscape, permitDesignations, hasErrors, diagnostics); + var left = BindPattern(node.Left, inputType, permitDesignations, hasErrors, diagnostics); + var right = BindPattern(node.Right, left.NarrowedType, permitDesignations, hasErrors, diagnostics); return new BoundBinaryPattern(node, disjunction: isDisjunction, left, right, inputType: inputType, narrowedType: right.NarrowedType, hasErrors); } } diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Query.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Query.cs index 6faf7b1b74e1f..357fcbd28c77f 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Query.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Query.cs @@ -814,7 +814,7 @@ private BoundExpression MakePair(CSharpSyntaxNode node, string field1Name, Bound return MakeConstruction(node, anonymousType, ImmutableArray.Create(field1Value, field2Value), diagnostics); AnonymousTypeField createField(string fieldName, BoundExpression fieldValue) => - new AnonymousTypeField(fieldName, fieldValue.Syntax.Location, TypeWithAnnotations.Create(TypeOrError(fieldValue)), RefKind.None, DeclarationScope.Unscoped); + new AnonymousTypeField(fieldName, fieldValue.Syntax.Location, TypeWithAnnotations.Create(TypeOrError(fieldValue)), RefKind.None, ScopedKind.None); } private TypeSymbol TypeOrError(BoundExpression e) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs index 26abf9fc31eb1..671b198c27783 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs @@ -243,7 +243,6 @@ private BoundStatement BindYieldReturnStatement(YieldStatementSyntax node, Bindi if (!argument.HasAnyErrors) { argument = GenerateConversionForAssignment(elementType, argument, diagnostics); - argument = ValidateEscape(argument, ReturnOnlyScope, isByRef: false, diagnostics: diagnostics); } else { @@ -1103,41 +1102,13 @@ protected BoundLocalDeclaration BindVariableDeclaration( hasErrors = true; } - if (localSymbol.Scope == DeclarationScope.ValueScoped && !declTypeOpt.Type.IsErrorTypeOrRefLikeType()) + if (localSymbol.Scope == ScopedKind.ScopedValue && !declTypeOpt.Type.IsErrorTypeOrRefLikeType()) { localDiagnostics.Add(ErrorCode.ERR_ScopedRefAndRefStructOnly, typeSyntax.Location); } localSymbol.SetTypeWithAnnotations(declTypeOpt); - if (initializerOpt != null) - { - if (UseUpdatedEscapeRules && localSymbol.Scope != DeclarationScope.Unscoped) - { - // If the local has a scoped modifier, then the lifetime is not inferred from - // the initializer. Validate the escape values for the initializer instead. - - Debug.Assert(localSymbol.RefKind == RefKind.None || - localSymbol.RefEscapeScope >= GetRefEscape(initializerOpt, LocalScopeDepth)); - - if (declTypeOpt.Type.IsRefLikeType) - { - initializerOpt = ValidateEscape(initializerOpt, localSymbol.ValEscapeScope, isByRef: false, diagnostics); - } - } - else - { - var currentScope = LocalScopeDepth; - - localSymbol.SetValEscape(GetValEscape(initializerOpt, currentScope)); - - if (localSymbol.RefKind != RefKind.None) - { - localSymbol.SetRefEscape(GetRefEscape(initializerOpt, currentScope)); - } - } - } - ImmutableArray arguments = BindDeclaratorArguments(declarator, localDiagnostics); if (kind == LocalDeclarationKind.FixedVariable || kind == LocalDeclarationKind.UsingVariable) @@ -1466,13 +1437,14 @@ private BoundExpression BindAssignment(AssignmentExpressionSyntax node, BindingD var rhsKind = isRef ? GetRequiredRHSValueKindForRefAssignment(op1) : BindValueKind.RValue; var op2 = BindValue(rhsExpr, diagnostics, rhsKind); - if (op1.Kind == BoundKind.DiscardExpression) + bool discardAssignment = op1.Kind == BoundKind.DiscardExpression; + if (discardAssignment) { op2 = BindToNaturalType(op2, diagnostics); op1 = InferTypeForDiscardAssignment((BoundDiscardExpression)op1, op2, diagnostics); } - return BindAssignment(node, op1, op2, isRef, verifyEscapeSafety: true, diagnostics); + return BindAssignment(node, op1, op2, isRef, diagnostics); } private static BindValueKind GetRequiredRHSValueKindForRefAssignment(BoundExpression boundLeft) @@ -1515,7 +1487,6 @@ private BoundAssignmentOperator BindAssignment( BoundExpression op1, BoundExpression op2, bool isRef, - bool verifyEscapeSafety, BindingDiagnosticBag diagnostics) { Debug.Assert(op1 != null); @@ -1542,64 +1513,6 @@ private BoundAssignmentOperator BindAssignment( { op2 = BindToNaturalType(op2, diagnostics); } - - if (verifyEscapeSafety) - { - if (isRef) - { - // https://github.com/dotnet/csharplang/blob/main/proposals/csharp-11.0/low-level-struct-improvements.md#rules-ref-reassignment - // For a ref reassignment in the form `e1 = ref e2` both of the following must be true: - // 1. `e2` must have *ref-safe-to-escape* at least as large as the *ref-safe-to-escape* of `e1` - // 2. `e1` must have the same *safe-to-escape* as `e2` - - var leftEscape = GetRefEscape(op1, LocalScopeDepth); - var rightEscape = GetRefEscape(op2, LocalScopeDepth); - if (leftEscape < rightEscape) - { - var errorCode = (rightEscape, this.InUnsafeRegion) switch - { - (Binder.ReturnOnlyScope, false) => ErrorCode.ERR_RefAssignReturnOnly, - (Binder.ReturnOnlyScope, true) => ErrorCode.WRN_RefAssignReturnOnly, - (_, false) => ErrorCode.ERR_RefAssignNarrower, - (_, true) => ErrorCode.WRN_RefAssignNarrower - }; - - Error(diagnostics, errorCode, node, getName(op1), op2.Syntax); - if (!this.InUnsafeRegion) - { - op2 = ToBadExpression(op2); - } - } - else if (op1.Kind is BoundKind.Local or BoundKind.Parameter) - { - leftEscape = GetValEscape(op1, LocalScopeDepth); - rightEscape = GetValEscape(op2, LocalScopeDepth); - - Debug.Assert(leftEscape == rightEscape || op1.Type.IsRefLikeType); - - // We only check if the safe-to-escape of e2 is wider than the safe-to-escape of e1 here, - // we don't check for equality. The case where the safe-to-escape of e2 is narrower than - // e1 is handled in the if (op1.Type.IsRefLikeType) { ... } block later. - if (leftEscape > rightEscape) - { - Debug.Assert(op1.Kind != BoundKind.Parameter); // If the assert fails, add a corresponding test. - - var errorCode = this.InUnsafeRegion ? ErrorCode.WRN_RefAssignValEscapeWider : ErrorCode.ERR_RefAssignValEscapeWider; - Error(diagnostics, errorCode, node, getName(op1), op2.Syntax); - if (!this.InUnsafeRegion) - { - op2 = ToBadExpression(op2); - } - } - } - } - - if (op1.Type.IsRefLikeType) - { - var leftEscape = GetValEscape(op1, LocalScopeDepth); - op2 = ValidateEscape(op2, leftEscape, isByRef: false, diagnostics); - } - } } else { @@ -1619,6 +1532,81 @@ private BoundAssignmentOperator BindAssignment( } return new BoundAssignmentOperator(node, op1, op2, isRef, type, hasErrors); + } + } + + partial class RefSafetyAnalysis + { + private void ValidateAssignment( + SyntaxNode node, + BoundExpression op1, + BoundExpression op2, + bool isRef, + BindingDiagnosticBag diagnostics) + { + Debug.Assert(op1 != null); + Debug.Assert(op2 != null); + + if (!op1.HasAnyErrors) + { + Debug.Assert(op1.Type is { }); + + bool hasErrors = false; + if (isRef) + { + // https://github.com/dotnet/csharplang/blob/main/proposals/csharp-11.0/low-level-struct-improvements.md#rules-ref-reassignment + // For a ref reassignment in the form `e1 = ref e2` both of the following must be true: + // 1. `e2` must have *ref-safe-to-escape* at least as large as the *ref-safe-to-escape* of `e1` + // 2. `e1` must have the same *safe-to-escape* as `e2` + + var leftEscape = GetRefEscape(op1, _localScopeDepth); + var rightEscape = GetRefEscape(op2, _localScopeDepth); + if (leftEscape < rightEscape) + { + var errorCode = (rightEscape, _inUnsafeRegion) switch + { + (Binder.ReturnOnlyScope, false) => ErrorCode.ERR_RefAssignReturnOnly, + (Binder.ReturnOnlyScope, true) => ErrorCode.WRN_RefAssignReturnOnly, + (_, false) => ErrorCode.ERR_RefAssignNarrower, + (_, true) => ErrorCode.WRN_RefAssignNarrower + }; + + Error(diagnostics, errorCode, node, getName(op1), op2.Syntax); + if (!_inUnsafeRegion) + { + hasErrors = true; + } + } + else if (op1.Kind is BoundKind.Local or BoundKind.Parameter) + { + leftEscape = GetValEscape(op1, _localScopeDepth); + rightEscape = GetValEscape(op2, _localScopeDepth); + + Debug.Assert(leftEscape == rightEscape || op1.Type.IsRefLikeType); + + // We only check if the safe-to-escape of e2 is wider than the safe-to-escape of e1 here, + // we don't check for equality. The case where the safe-to-escape of e2 is narrower than + // e1 is handled in the if (op1.Type.IsRefLikeType) { ... } block later. + if (leftEscape > rightEscape) + { + Debug.Assert(op1.Kind != BoundKind.Parameter); // If the assert fails, add a corresponding test. + + var errorCode = _inUnsafeRegion ? ErrorCode.WRN_RefAssignValEscapeWider : ErrorCode.ERR_RefAssignValEscapeWider; + Error(diagnostics, errorCode, node, getName(op1), op2.Syntax); + if (!_inUnsafeRegion) + { + hasErrors = true; + } + } + } + } + + if (!hasErrors && op1.Type.IsRefLikeType) + { + var leftEscape = GetValEscape(op1, _localScopeDepth); + ValidateEscape(op2, leftEscape, isByRef: false, diagnostics); + } + } static object getName(BoundExpression expr) { @@ -1639,7 +1627,10 @@ static object getName(BoundExpression expr) return ""; } } + } + partial class Binder + { internal static PropertySymbol GetPropertySymbol(BoundExpression expr, out BoundExpression receiver, out SyntaxNode propertySyntax) { if (expr is null) @@ -1858,13 +1849,6 @@ protected virtual LocalFunctionSymbol LookupLocalFunction(SyntaxToken nameToken) return Next.LookupLocalFunction(nameToken); } - /// - /// Returns a value that tells how many local scopes are visible, including the current. - /// I.E. outside of any method will be 0 - /// immediately inside a method - 1 - /// - internal virtual uint LocalScopeDepth => Next.LocalScopeDepth; - internal virtual BoundBlock BindEmbeddedBlock(BlockSyntax node, BindingDiagnosticBag diagnostics) { return BindBlock(node, diagnostics); @@ -1907,6 +1891,7 @@ private BoundBlock FinishBindBlockParts(CSharpSyntaxNode node, ImmutableArray Binder.CallingMethodScope; - protected override bool InExecutableBinder => false; protected override SyntaxNode? EnclosingNameofArgument => null; internal override bool IsInsideNameof => false; @@ -203,7 +201,7 @@ internal override void BindPatternSwitchLabelForInference(CasePatternSwitchLabel throw ExceptionUtilities.Unreachable(); } - internal override BoundSwitchExpressionArm BindSwitchExpressionArm(SwitchExpressionArmSyntax node, TypeSymbol switchGoverningType, uint switchGoverningValEscape, BindingDiagnosticBag diagnostics) + internal override BoundSwitchExpressionArm BindSwitchExpressionArm(SwitchExpressionArmSyntax node, TypeSymbol switchGoverningType, BindingDiagnosticBag diagnostics) { // There's supposed to be an overrider of this method (e.g. SwitchExpressionArmBinder) for the arm in the chain. throw ExceptionUtilities.Unreachable(); diff --git a/src/Compilers/CSharp/Portable/Binder/DecisionDagBuilder.cs b/src/Compilers/CSharp/Portable/Binder/DecisionDagBuilder.cs index 557d1880d333b..4a7f3b64ae7a4 100644 --- a/src/Compilers/CSharp/Portable/Binder/DecisionDagBuilder.cs +++ b/src/Compilers/CSharp/Portable/Binder/DecisionDagBuilder.cs @@ -1853,7 +1853,7 @@ public StateForCase( /// /// Is the pattern in a state in which it is fully matched and there is no when clause? /// - public bool IsFullyMatched => RemainingTests is Tests.True && (WhenClause is null || WhenClause.ConstantValue == ConstantValue.True); + public bool IsFullyMatched => RemainingTests is Tests.True && (WhenClause is null || WhenClause.ConstantValueOpt == ConstantValue.True); /// /// Is the pattern fully matched and ready for the when clause to be evaluated (if any)? diff --git a/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs b/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs index 0f9caddc63720..9fdaee9f10b42 100644 --- a/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs @@ -182,7 +182,7 @@ internal override BoundStatement BindForEachDeconstruction(BindingDiagnosticBag ExpressionSyntax variables = ((ForEachVariableStatementSyntax)_syntax).Variable; // Tracking narrowest safe-to-escape scope by default, the proper val escape will be set when doing full binding of the foreach statement - var valuePlaceholder = new BoundDeconstructValuePlaceholder(_syntax.Expression, variableSymbol: null, this.LocalScopeDepth, inferredType.Type ?? CreateErrorType("var")); + var valuePlaceholder = new BoundDeconstructValuePlaceholder(_syntax.Expression, variableSymbol: null, isDiscardExpression: false, inferredType.Type ?? CreateErrorType("var")); DeclarationExpressionSyntax declaration = null; ExpressionSyntax expression = null; @@ -237,7 +237,7 @@ private BoundForEachStatement BindForEachPartsWorker(BindingDiagnosticBag diagno { var expr = _syntax.Expression; ReportBadAwaitDiagnostics(expr, _syntax.AwaitKeyword.GetLocation(), diagnostics, ref hasErrors); - var placeholder = new BoundAwaitableValuePlaceholder(expr, valEscape: this.LocalScopeDepth, builder.MoveNextInfo?.Method.ReturnType ?? CreateErrorType()); + var placeholder = new BoundAwaitableValuePlaceholder(expr, builder.MoveNextInfo?.Method.ReturnType ?? CreateErrorType()); awaitInfo = BindAwaitInfo(placeholder, expr, diagnostics, ref hasErrors); if (!hasErrors && awaitInfo.GetResult?.ReturnType.SpecialType != SpecialType.System_Boolean) @@ -252,7 +252,6 @@ private BoundForEachStatement BindForEachPartsWorker(BindingDiagnosticBag diagno bool hasNameConflicts = false; BoundForEachDeconstructStep deconstructStep = null; BoundExpression iterationErrorExpression = null; - uint collectionEscape = GetValEscape(collectionExpr, this.LocalScopeDepth); switch (_syntax.Kind()) { case SyntaxKind.ForEachStatement: @@ -298,20 +297,14 @@ private BoundForEachStatement BindForEachPartsWorker(BindingDiagnosticBag diagno SourceLocalSymbol local = this.IterationVariable; local.SetTypeWithAnnotations(declType); - local.SetValEscape(collectionEscape); - if (local.Scope == DeclarationScope.ValueScoped && !declType.Type.IsErrorTypeOrRefLikeType()) + if (local.Scope == ScopedKind.ScopedValue && !declType.Type.IsErrorTypeOrRefLikeType()) { diagnostics.Add(ErrorCode.ERR_ScopedRefAndRefStructOnly, typeSyntax.Location); } if (local.RefKind != RefKind.None) { - // The ref-escape of a ref-returning property is decided - // by the value escape of its receiver, in this case the - // collection - local.SetRefEscape(collectionEscape); - if (CheckRefLocalInAsyncOrIteratorMethod(local.IdentifierToken, diagnostics)) { hasErrors = true; @@ -355,7 +348,7 @@ private BoundForEachStatement BindForEachPartsWorker(BindingDiagnosticBag diagno var variables = node.Variable; if (variables.IsDeconstructionLeft()) { - var valuePlaceholder = new BoundDeconstructValuePlaceholder(_syntax.Expression, variableSymbol: null, collectionEscape, iterationVariableType.Type).MakeCompilerGenerated(); + var valuePlaceholder = new BoundDeconstructValuePlaceholder(_syntax.Expression, variableSymbol: null, isDiscardExpression: false, iterationVariableType.Type).MakeCompilerGenerated(); DeclarationExpressionSyntax declaration = null; ExpressionSyntax expression = null; BoundDeconstructionAssignmentOperator deconstruction = BindDeconstruction( @@ -603,7 +596,7 @@ private bool GetAwaitDisposeAsyncInfo(ref ForEachEnumeratorInfo.Builder builder, var expr = _syntax.Expression; ReportBadAwaitDiagnostics(expr, _syntax.AwaitKeyword.GetLocation(), diagnostics, ref hasErrors); - var placeholder = new BoundAwaitableValuePlaceholder(expr, valEscape: this.LocalScopeDepth, awaitableType); + var placeholder = new BoundAwaitableValuePlaceholder(expr, awaitableType); builder.DisposeAwaitableInfo = BindAwaitInfo(placeholder, expr, diagnostics, ref hasErrors); return hasErrors; } @@ -1003,7 +996,7 @@ private EnumeratorResult SatisfiesIEnumerableInterfaces(ref ForEachEnumeratorInf private bool ReportConstantNullCollectionExpr(BoundExpression collectionExpr, BindingDiagnosticBag diagnostics) { - if (collectionExpr.ConstantValue is { IsNull: true }) + if (collectionExpr.ConstantValueOpt is { IsNull: true }) { // Spec seems to refer to null literals, but Dev10 reports anything known to be null. diagnostics.Add(ErrorCode.ERR_NullNotValid, _syntax.Expression.Location); diff --git a/src/Compilers/CSharp/Portable/Binder/InContainerBinder.cs b/src/Compilers/CSharp/Portable/Binder/InContainerBinder.cs index 2e7edb6dbdad1..d5f45168cd481 100644 --- a/src/Compilers/CSharp/Portable/Binder/InContainerBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/InContainerBinder.cs @@ -142,7 +142,5 @@ protected override LocalFunctionSymbol LookupLocalFunction(SyntaxToken nameToken { return null; } - - internal override uint LocalScopeDepth => Binder.CallingMethodScope; } } diff --git a/src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs b/src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs index 83b4f0218a50c..cd9181c6b0805 100644 --- a/src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs @@ -8,7 +8,6 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; -using System.Threading; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Roslyn.Utilities; @@ -67,8 +66,6 @@ protected override LocalFunctionSymbol LookupLocalFunction(SyntaxToken nameToken return null; } - internal override uint LocalScopeDepth => Binder.CurrentMethodScope; - protected override bool InExecutableBinder => true; internal override Symbol ContainingMemberOrLambda diff --git a/src/Compilers/CSharp/Portable/Binder/LocalScopeBinder.cs b/src/Compilers/CSharp/Portable/Binder/LocalScopeBinder.cs index c4810acd4e57e..7b4d9c029e45b 100644 --- a/src/Compilers/CSharp/Portable/Binder/LocalScopeBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/LocalScopeBinder.cs @@ -4,8 +4,6 @@ #nullable disable -using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using Microsoft.CodeAnalysis.CSharp.Symbols; @@ -20,7 +18,6 @@ internal partial class LocalScopeBinder : Binder private ImmutableArray _locals; private ImmutableArray _localFunctions; private ImmutableArray _labels; - private readonly uint _localScopeDepth; internal LocalScopeBinder(Binder next) : this(next, next.Flags) @@ -30,35 +27,6 @@ internal LocalScopeBinder(Binder next) internal LocalScopeBinder(Binder next, BinderFlags flags) : base(next, flags) { - var parentDepth = next.LocalScopeDepth; - - if (parentDepth != Binder.CurrentMethodScope) - { - _localScopeDepth = parentDepth + 1; - } - else - { - //NOTE: TopLevel is special. - //For our purpose parameters and top level locals are on that level. - var parentScope = next; - while (parentScope != null) - { - if (parentScope is InMethodBinder || parentScope is WithLambdaParametersBinder) - { - _localScopeDepth = Binder.CurrentMethodScope; - break; - } - - if (parentScope is LocalScopeBinder) - { - _localScopeDepth = Binder.CurrentMethodScope + 1; - break; - } - - parentScope = parentScope.Next; - Debug.Assert(parentScope != null); - } - } } internal sealed override ImmutableArray Locals @@ -404,8 +372,6 @@ protected override LocalFunctionSymbol LookupLocalFunction(SyntaxToken nameToken return base.LookupLocalFunction(nameToken); } - internal override uint LocalScopeDepth => _localScopeDepth; - internal override void LookupSymbolsInSingleBinder( LookupResult result, string name, int arity, ConsList basesBeingResolved, LookupOptions options, Binder originalBinder, bool diagnose, ref CompoundUseSiteInfo useSiteInfo) { diff --git a/src/Compilers/CSharp/Portable/Binder/LockBinder.cs b/src/Compilers/CSharp/Portable/Binder/LockBinder.cs index e6ea4a54f0588..7a050ef28f219 100644 --- a/src/Compilers/CSharp/Portable/Binder/LockBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/LockBinder.cs @@ -43,7 +43,7 @@ internal override BoundStatement BindLockStatementParts(BindingDiagnosticBag dia if ((object)exprType == null) { - if (expr.ConstantValue != ConstantValue.Null || Compilation.FeatureStrictEnabled) // Dev10 allows the null literal. + if (expr.ConstantValueOpt != ConstantValue.Null || Compilation.FeatureStrictEnabled) // Dev10 allows the null literal. { Error(diagnostics, ErrorCode.ERR_LockNeedsReference, exprSyntax, expr.Display); hasErrors = true; diff --git a/src/Compilers/CSharp/Portable/Binder/RefSafetyAnalysis.cs b/src/Compilers/CSharp/Portable/Binder/RefSafetyAnalysis.cs new file mode 100644 index 0000000000000..a6cffee487308 --- /dev/null +++ b/src/Compilers/CSharp/Portable/Binder/RefSafetyAnalysis.cs @@ -0,0 +1,897 @@ +// 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 System.Diagnostics; +using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.PooledObjects; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CSharp +{ + internal sealed partial class RefSafetyAnalysis : BoundTreeWalkerWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator + { + internal static void Analyze(CSharpCompilation compilation, Symbol symbol, BoundNode node, BindingDiagnosticBag diagnostics) + { + var visitor = new RefSafetyAnalysis( + compilation, + symbol, + inUnsafeRegion: InUnsafeMethod(symbol), + useUpdatedEscapeRules: symbol.ContainingModule.UseUpdatedEscapeRules, + diagnostics); + try + { + visitor.Visit(node); + } + catch (CancelledByStackGuardException e) + { + e.AddAnError(diagnostics); + } + } + + internal static void Analyze(CSharpCompilation compilation, Symbol symbol, ImmutableArray fieldAndPropertyInitializers, BindingDiagnosticBag diagnostics) + { + var visitor = new RefSafetyAnalysis( + compilation, + symbol, + inUnsafeRegion: InUnsafeMethod(symbol), + useUpdatedEscapeRules: symbol.ContainingModule.UseUpdatedEscapeRules, + diagnostics); + foreach (var initializer in fieldAndPropertyInitializers) + { + try + { + visitor.VisitFieldOrPropertyInitializer(initializer); + } + catch (CancelledByStackGuardException e) + { + e.AddAnError(diagnostics); + } + } + } + + private static bool InUnsafeMethod(Symbol symbol) + { + if (symbol is SourceMemberMethodSymbol { IsUnsafe: true }) + { + return true; + } + + var type = symbol.ContainingType; + while (type is { }) + { + var def = type.OriginalDefinition; + if (def is SourceMemberContainerTypeSymbol { IsUnsafe: true }) + { + return true; + } + type = def.ContainingType; + } + + return false; + } + + private readonly CSharpCompilation _compilation; + private readonly Symbol _symbol; + private readonly bool _useUpdatedEscapeRules; + private readonly BindingDiagnosticBag _diagnostics; + private bool _inUnsafeRegion; + private uint _localScopeDepth; + private Dictionary? _localEscapeScopes; + private Dictionary? _placeholderScopes; + private uint _patternInputValEscape; + + private RefSafetyAnalysis( + CSharpCompilation compilation, + Symbol symbol, + bool inUnsafeRegion, + bool useUpdatedEscapeRules, + BindingDiagnosticBag diagnostics, + Dictionary? localEscapeScopes = null) + { + _compilation = compilation; + _symbol = symbol; + _useUpdatedEscapeRules = useUpdatedEscapeRules; + _diagnostics = diagnostics; + _inUnsafeRegion = inUnsafeRegion; + // _localScopeDepth is incremented at each block in the method, including the + // outermost. To ensure that locals in the outermost block are considered at + // the same depth as parameters, _localScopeDepth is initialized to one less. + _localScopeDepth = Binder.CurrentMethodScope - 1; + _localEscapeScopes = localEscapeScopes; + } + + private ref struct LocalScope + { + private readonly RefSafetyAnalysis _analysis; + private readonly ImmutableArray _locals; + + public LocalScope(RefSafetyAnalysis analysis, ImmutableArray locals) + { + _analysis = analysis; + _locals = locals; + _analysis._localScopeDepth++; + foreach (var local in locals) + { + _analysis.AddLocalScopes(local, refEscapeScope: _analysis._localScopeDepth, valEscapeScope: Binder.CallingMethodScope); + } + } + + public void Dispose() + { + foreach (var local in _locals) + { + _analysis.RemoveLocalScopes(local); + } + _analysis._localScopeDepth--; + } + } + + private ref struct UnsafeRegion + { + private readonly RefSafetyAnalysis _analysis; + private readonly bool _previousRegion; + + public UnsafeRegion(RefSafetyAnalysis analysis, bool inUnsafeRegion) + { + _analysis = analysis; + _previousRegion = analysis._inUnsafeRegion; + _analysis._inUnsafeRegion = inUnsafeRegion; + } + + public void Dispose() + { + _analysis._inUnsafeRegion = _previousRegion; + } + } + + private ref struct PatternInput + { + private readonly RefSafetyAnalysis _analysis; + private readonly uint _previousInputValEscape; + + public PatternInput(RefSafetyAnalysis analysis, uint patternInputValEscape) + { + _analysis = analysis; + _previousInputValEscape = analysis._patternInputValEscape; + _analysis._patternInputValEscape = patternInputValEscape; + } + + public void Dispose() + { + _analysis._patternInputValEscape = _previousInputValEscape; + } + } + + private ref struct PlaceholderRegion + { + private readonly RefSafetyAnalysis _analysis; + private readonly ArrayBuilder<(BoundValuePlaceholderBase, uint)> _placeholders; + + public PlaceholderRegion(RefSafetyAnalysis analysis, ArrayBuilder<(BoundValuePlaceholderBase, uint)> placeholders) + { + _analysis = analysis; + _placeholders = placeholders; + foreach (var (placeholder, valEscapeScope) in placeholders) + { + _analysis.AddPlaceholderScope(placeholder, valEscapeScope); + } + } + + public void Dispose() + { + foreach (var (placeholder, _) in _placeholders) + { + _analysis.RemovePlaceholderScope(placeholder); + } + _placeholders.Free(); + } + } + + private (uint RefEscapeScope, uint ValEscapeScope) GetLocalScopes(LocalSymbol local) + { + Debug.Assert(_localEscapeScopes is { }); + return _localEscapeScopes[local]; + } + + private void SetLocalScopes(LocalSymbol local, uint refEscapeScope, uint valEscapeScope) + { + Debug.Assert(_localEscapeScopes is { }); + _localEscapeScopes[local] = (refEscapeScope, valEscapeScope); + } + + private void AddPlaceholderScope(BoundValuePlaceholderBase placeholder, uint valEscapeScope) + { + _placeholderScopes ??= new Dictionary(); + _placeholderScopes.Add(placeholder, valEscapeScope); + } + +#pragma warning disable IDE0060 + private void RemovePlaceholderScope(BoundValuePlaceholderBase placeholder) + { + Debug.Assert(_placeholderScopes is { }); + // https://github.com/dotnet/roslyn/issues/65961: Currently, analysis may require subsequent calls + // to GetRefEscape(), etc. for the same expression so we cannot remove placeholders eagerly. + //_placeholderScopes.Remove(placeholder); + } +#pragma warning restore IDE0060 + + private uint GetPlaceholderScope(BoundValuePlaceholderBase placeholder) + { + Debug.Assert(_placeholderScopes is { }); + return _placeholderScopes[placeholder]; + } + + public override BoundNode? VisitBlock(BoundBlock node) + { + using var _1 = new UnsafeRegion(this, _inUnsafeRegion || node.HasUnsafeModifier); + using var _2 = new LocalScope(this, node.Locals); + return base.VisitBlock(node); + } + + public override BoundNode? Visit(BoundNode? node) + { +#if DEBUG + if (node is BoundValuePlaceholderBase placeholder + // CheckValEscapeOfObjectInitializer() does not use BoundObjectOrCollectionValuePlaceholder. + // CheckInterpolatedStringHandlerConversionEscape() does not use BoundInterpolatedStringHandlerPlaceholder. + && node is not (BoundObjectOrCollectionValuePlaceholder or BoundInterpolatedStringHandlerPlaceholder)) + { + Debug.Assert(_placeholderScopes?.ContainsKey(placeholder) == true); + } +#endif + return base.Visit(node); + } + + private void VisitFieldOrPropertyInitializer(BoundInitializer initializer) + { + var fieldEqualsValue = (BoundFieldEqualsValue)initializer; + var field = fieldEqualsValue.Field; + var value = fieldEqualsValue.Value; + + using var _ = new LocalScope(this, fieldEqualsValue.Locals); + + base.Visit(value); + + ValidateEscape(value, Binder.CallingMethodScope, isByRef: field.RefKind != RefKind.None, _diagnostics); + } + + public override BoundNode? VisitLocalFunctionStatement(BoundLocalFunctionStatement node) + { + var localFunction = node.Symbol; + // https://github.com/dotnet/roslyn/issues/65353: We should not reuse _localEscapeScopes + // across nested local functions or lambdas because _localScopeDepth is reset when entering + // the function or lambda so the scopes across the methods are unrelated. + var analysis = new RefSafetyAnalysis(_compilation, localFunction, _inUnsafeRegion || localFunction.IsUnsafe, _useUpdatedEscapeRules, _diagnostics, _localEscapeScopes); + analysis.Visit(node.BlockBody); + analysis.Visit(node.ExpressionBody); + return null; + } + + public override BoundNode? VisitLambda(BoundLambda node) + { + var lambda = node.Symbol; + // https://github.com/dotnet/roslyn/issues/65353: We should not reuse _localEscapeScopes + // across nested local functions or lambdas because _localScopeDepth is reset when entering + // the function or lambda so the scopes across the methods are unrelated. + var analysis = new RefSafetyAnalysis(_compilation, lambda, _inUnsafeRegion, _useUpdatedEscapeRules, _diagnostics, _localEscapeScopes); + analysis.Visit(node.Body); + return null; + } + + public override BoundNode? VisitConstructorMethodBody(BoundConstructorMethodBody node) + { + using var _ = new LocalScope(this, node.Locals); + return base.VisitConstructorMethodBody(node); + } + + public override BoundNode? VisitForStatement(BoundForStatement node) + { + using var outerLocals = new LocalScope(this, node.OuterLocals); + using var innerLocals = new LocalScope(this, node.InnerLocals); + return base.VisitForStatement(node); + } + + public override BoundNode? VisitUsingStatement(BoundUsingStatement node) + { + using var _ = new LocalScope(this, node.Locals); + + var placeholders = ArrayBuilder<(BoundValuePlaceholderBase, uint)>.GetInstance(); + if (node.AwaitOpt is { } awaitableInfo) + { + uint valEscapeScope = node.ExpressionOpt is { } expr + ? GetValEscape(expr, _localScopeDepth) + : _localScopeDepth; + GetAwaitableInstancePlaceholders(placeholders, awaitableInfo, valEscapeScope); + } + + using var region = new PlaceholderRegion(this, placeholders); + return base.VisitUsingStatement(node); + } + + public override BoundNode? VisitUsingLocalDeclarations(BoundUsingLocalDeclarations node) + { + var placeholders = ArrayBuilder<(BoundValuePlaceholderBase, uint)>.GetInstance(); + if (node.AwaitOpt is { } awaitableInfo) + { + GetAwaitableInstancePlaceholders(placeholders, awaitableInfo, _localScopeDepth); + } + + using var _ = new PlaceholderRegion(this, placeholders); + return base.VisitUsingLocalDeclarations(node); + } + + public override BoundNode? VisitFixedStatement(BoundFixedStatement node) + { + using var _ = new LocalScope(this, node.Locals); + return base.VisitFixedStatement(node); + } + + public override BoundNode? VisitDoStatement(BoundDoStatement node) + { + using var _ = new LocalScope(this, node.Locals); + return base.VisitDoStatement(node); + } + + public override BoundNode? VisitWhileStatement(BoundWhileStatement node) + { + using var _ = new LocalScope(this, node.Locals); + return base.VisitWhileStatement(node); + } + + public override BoundNode? VisitSwitchStatement(BoundSwitchStatement node) + { + using var _1 = new LocalScope(this, node.InnerLocals); + using var _2 = new PatternInput(this, GetValEscape(node.Expression, _localScopeDepth)); + base.VisitSwitchStatement(node); + return null; + } + + public override BoundNode? VisitConvertedSwitchExpression(BoundConvertedSwitchExpression node) + { + using var _ = new PatternInput(this, GetValEscape(node.Expression, _localScopeDepth)); + base.VisitConvertedSwitchExpression(node); + return null; + } + + public override BoundNode? VisitSwitchSection(BoundSwitchSection node) + { + using var _ = new LocalScope(this, node.Locals); + return base.VisitSwitchSection(node); + } + + public override BoundNode? VisitSwitchExpressionArm(BoundSwitchExpressionArm node) + { + using var _ = new LocalScope(this, node.Locals); + return base.VisitSwitchExpressionArm(node); + } + + public override BoundNode? VisitCatchBlock(BoundCatchBlock node) + { + using var _ = new LocalScope(this, node.Locals); + return base.VisitCatchBlock(node); + } + + public override BoundNode? VisitLocal(BoundLocal node) + { + // _localEscapeScopes may be null for locals in top-level statements. + Debug.Assert(_localEscapeScopes?.ContainsKey(node.LocalSymbol) == true || + (node.LocalSymbol.ContainingSymbol is SynthesizedSimpleProgramEntryPointSymbol entryPoint && _symbol != entryPoint)); + + return base.VisitLocal(node); + } + + private void AddLocalScopes(LocalSymbol local, uint refEscapeScope, uint valEscapeScope) + { + // From https://github.com/dotnet/csharplang/blob/main/csharp-11.0/proposals/low-level-struct-improvements.md: + // + // | Parameter or Local | ref-safe-to-escape | safe-to-escape | + // |------------------------|--------------------|----------------| + // | Span s | current method | calling method | + // | scoped Span s | current method | current method | + // | ref Span s | calling method | calling method | + // | scoped ref Span s | current method | calling method | + + var scopedModifier = _useUpdatedEscapeRules ? local.Scope : ScopedKind.None; + if (scopedModifier != ScopedKind.None) + { + refEscapeScope = scopedModifier == ScopedKind.ScopedRef ? + _localScopeDepth : + Binder.CurrentMethodScope; + valEscapeScope = scopedModifier == ScopedKind.ScopedValue ? + _localScopeDepth : + Binder.CallingMethodScope; + } + + _localEscapeScopes ??= new Dictionary(); + _localEscapeScopes.Add(local, (refEscapeScope, valEscapeScope)); + } + +#pragma warning disable IDE0060 + private void RemoveLocalScopes(LocalSymbol local) + { + Debug.Assert(_localEscapeScopes is { }); + // https://github.com/dotnet/roslyn/issues/65961: Currently, analysis may require subsequent calls + // to GetRefEscape(), etc. for the same expression so we cannot remove locals eagerly. + //_localEscapeScopes.Remove(local); + } +#pragma warning restore IDE0060 + + public override BoundNode? VisitLocalDeclaration(BoundLocalDeclaration node) + { + base.VisitLocalDeclaration(node); + + if (node.InitializerOpt is { } initializer) + { + var localSymbol = (SourceLocalSymbol)node.LocalSymbol; + (uint refEscapeScope, uint valEscapeScope) = GetLocalScopes(localSymbol); + + if (_useUpdatedEscapeRules && localSymbol.Scope != ScopedKind.None) + { + // If the local has a scoped modifier, then the lifetime is not inferred from + // the initializer. Validate the escape values for the initializer instead. + + Debug.Assert(localSymbol.RefKind == RefKind.None || + refEscapeScope >= GetRefEscape(initializer, _localScopeDepth)); + + if (node.DeclaredTypeOpt?.Type.IsRefLikeType == true) + { + ValidateEscape(initializer, valEscapeScope, isByRef: false, _diagnostics); + } + } + else + { + // default to the current scope in case we need to handle self-referential error cases. + SetLocalScopes(localSymbol, _localScopeDepth, _localScopeDepth); + + valEscapeScope = GetValEscape(initializer, _localScopeDepth); + if (localSymbol.RefKind != RefKind.None) + { + refEscapeScope = GetRefEscape(initializer, _localScopeDepth); + } + + SetLocalScopes(localSymbol, refEscapeScope, valEscapeScope); + } + } + + return null; + } + + public override BoundNode? VisitReturnStatement(BoundReturnStatement node) + { + base.VisitReturnStatement(node); + if (node.ExpressionOpt is { Type: { } } expr) + { + ValidateEscape(expr, Binder.ReturnOnlyScope, node.RefKind != RefKind.None, _diagnostics); + } + return null; + } + + public override BoundNode? VisitYieldReturnStatement(BoundYieldReturnStatement node) + { + base.VisitYieldReturnStatement(node); + if (node.Expression is { Type: { } } expr) + { + ValidateEscape(expr, Binder.ReturnOnlyScope, isByRef: false, _diagnostics); + } + return null; + } + + public override BoundNode? VisitAssignmentOperator(BoundAssignmentOperator node) + { + base.VisitAssignmentOperator(node); + if (node.Left.Kind != BoundKind.DiscardExpression) + { + ValidateAssignment(node.Syntax, node.Left, node.Right, node.IsRef, _diagnostics); + } + return null; + } + + public override BoundNode? VisitIsPatternExpression(BoundIsPatternExpression node) + { + using var _ = new PatternInput(this, GetValEscape(node.Expression, _localScopeDepth)); + return base.VisitIsPatternExpression(node); + } + + public override BoundNode? VisitDeclarationPattern(BoundDeclarationPattern node) + { + SetPatternLocalScopes(node); + + using var _ = new PatternInput(this, getDeclarationValEscape(node.DeclaredType, _patternInputValEscape)); + return base.VisitDeclarationPattern(node); + + static uint getDeclarationValEscape(BoundTypeExpression typeExpression, uint valEscape) + { + return typeExpression.Type.IsRefLikeType ? valEscape : Binder.CallingMethodScope; + } + } + + public override BoundNode? VisitListPattern(BoundListPattern node) + { + SetPatternLocalScopes(node); + return base.VisitListPattern(node); + } + + public override BoundNode? VisitRecursivePattern(BoundRecursivePattern node) + { + SetPatternLocalScopes(node); + return base.VisitRecursivePattern(node); + } + + public override BoundNode? VisitPositionalSubpattern(BoundPositionalSubpattern node) + { + using var _ = new PatternInput(this, getPositionalValEscape(node.Symbol, _patternInputValEscape)); + return base.VisitPositionalSubpattern(node); + + static uint getPositionalValEscape(Symbol? symbol, uint valEscape) + { + return symbol is null + ? valEscape + : symbol.GetTypeOrReturnType().IsRefLikeType() ? valEscape : Binder.CallingMethodScope; + } + } + + public override BoundNode? VisitPropertySubpattern(BoundPropertySubpattern node) + { + using var _ = new PatternInput(this, getMemberValEscape(node.Member, _patternInputValEscape)); + return base.VisitPropertySubpattern(node); + + static uint getMemberValEscape(BoundPropertySubpatternMember? member, uint valEscape) + { + if (member is null) return valEscape; + valEscape = getMemberValEscape(member.Receiver, valEscape); + return member.Type.IsRefLikeType ? valEscape : Binder.CallingMethodScope; + } + } + + private void SetPatternLocalScopes(BoundObjectPattern pattern) + { + if (pattern.Variable is LocalSymbol local) + { + SetLocalScopes(local, _localScopeDepth, _patternInputValEscape); + } + } + + public override BoundNode? VisitConditionalOperator(BoundConditionalOperator node) + { + base.VisitConditionalOperator(node); + if (node.IsRef) + { + ValidateRefConditionalOperator(node.Syntax, node.Consequence, node.Alternative, _diagnostics); + } + return null; + } + + private PlaceholderRegion GetArgumentPlaceholders(BoundExpression? receiverOpt, ImmutableArray arguments) + { + var placeholders = ArrayBuilder<(BoundValuePlaceholderBase, uint)>.GetInstance(); + foreach (var arg in arguments) + { + if (arg is BoundConversion { ConversionKind: ConversionKind.InterpolatedStringHandler, Operand: BoundInterpolatedString or BoundBinaryOperator } conversion) + { + var interpolationData = conversion.Operand.GetInterpolatedStringHandlerData(); + GetInterpolatedStringPlaceholders(placeholders, interpolationData, receiverOpt, arguments); + } + } + return new PlaceholderRegion(this, placeholders); + } + + public override BoundNode? VisitCall(BoundCall node) + { + using var _ = GetArgumentPlaceholders(node.ReceiverOpt, node.Arguments); + base.VisitCall(node); + + if (!node.HasErrors) + { + var method = node.Method; + CheckInvocationArgMixing( + node.Syntax, + method, + node.ReceiverOpt, + method.Parameters, + node.Arguments, + node.ArgumentRefKindsOpt, + node.ArgsToParamsOpt, + _localScopeDepth, + _diagnostics); + } + + return null; + } + + private void GetInterpolatedStringPlaceholders( + ArrayBuilder<(BoundValuePlaceholderBase, uint)> placeholders, + in InterpolatedStringHandlerData interpolationData, + BoundExpression? receiver, + ImmutableArray arguments) + { + placeholders.Add((interpolationData.ReceiverPlaceholder, _localScopeDepth)); + + foreach (var placeholder in interpolationData.ArgumentPlaceholders) + { + uint valEscapeScope; + int argIndex = placeholder.ArgumentIndex; + switch (argIndex) + { + case BoundInterpolatedStringArgumentPlaceholder.InstanceParameter: + Debug.Assert(receiver != null); + valEscapeScope = receiver.GetRefKind().IsWritableReference() ? GetRefEscape(receiver, _localScopeDepth) : GetValEscape(receiver, _localScopeDepth); + break; + case BoundInterpolatedStringArgumentPlaceholder.TrailingConstructorValidityParameter: + case BoundInterpolatedStringArgumentPlaceholder.UnspecifiedParameter: + continue; + case >= 0: + valEscapeScope = GetValEscape(arguments[argIndex], _localScopeDepth); + break; + default: + throw ExceptionUtilities.UnexpectedValue(placeholder.ArgumentIndex); + } + placeholders.Add((placeholder, valEscapeScope)); + } + } + + public override BoundNode? VisitObjectCreationExpression(BoundObjectCreationExpression node) + { + using var _ = GetArgumentPlaceholders(receiverOpt: null, node.Arguments); + base.VisitObjectCreationExpression(node); + + if (!node.HasErrors) + { + var constructor = node.Constructor; + CheckInvocationArgMixing( + node.Syntax, + constructor, + receiverOpt: null, + constructor.Parameters, + node.Arguments, + node.ArgumentRefKindsOpt, + node.ArgsToParamsOpt, + _localScopeDepth, + _diagnostics); + } + + return null; + } + + public override BoundNode? VisitIndexerAccess(BoundIndexerAccess node) + { + using var _ = GetArgumentPlaceholders(node.ReceiverOpt, node.Arguments); + base.VisitIndexerAccess(node); + + if (!node.HasErrors) + { + var indexer = node.Indexer; + CheckInvocationArgMixing( + node.Syntax, + indexer, + node.ReceiverOpt, + indexer.Parameters, + node.Arguments, + node.ArgumentRefKindsOpt, + node.ArgsToParamsOpt, + _localScopeDepth, + _diagnostics); + } + + return null; + } + + public override BoundNode? VisitFunctionPointerInvocation(BoundFunctionPointerInvocation node) + { + using var _ = GetArgumentPlaceholders(receiverOpt: null, node.Arguments); + base.VisitFunctionPointerInvocation(node); + + if (!node.HasErrors) + { + var method = node.FunctionPointer.Signature; + CheckInvocationArgMixing( + node.Syntax, + method, + receiverOpt: null, + method.Parameters, + node.Arguments, + node.ArgumentRefKindsOpt, + argsToParamsOpt: default, + _localScopeDepth, + _diagnostics); + } + + return null; + } + + public override BoundNode? VisitAwaitExpression(BoundAwaitExpression node) + { + var placeholders = ArrayBuilder<(BoundValuePlaceholderBase, uint)>.GetInstance(); + GetAwaitableInstancePlaceholders(placeholders, node.AwaitableInfo, GetValEscape(node.Expression, _localScopeDepth)); + using var _ = new PlaceholderRegion(this, placeholders); + base.VisitAwaitExpression(node); + return null; + } + + private void GetAwaitableInstancePlaceholders(ArrayBuilder<(BoundValuePlaceholderBase, uint)> placeholders, BoundAwaitableInfo awaitableInfo, uint valEscapeScope) + { + if (awaitableInfo.AwaitableInstancePlaceholder is { } placeholder) + { + placeholders.Add((placeholder, valEscapeScope)); + } + } + + // Based on NullableWalker.VisitDeconstructionAssignmentOperator(). + public override BoundNode? VisitDeconstructionAssignmentOperator(BoundDeconstructionAssignmentOperator node) + { + base.VisitDeconstructionAssignmentOperator(node); + + var left = node.Left; + var right = node.Right; + var variables = GetDeconstructionAssignmentVariables(left); + VisitDeconstructionArguments(variables, right.Syntax, right.Conversion, right.Operand); + variables.FreeAll(v => v.NestedVariables); + return null; + } + + private void VisitDeconstructionArguments(ArrayBuilder variables, SyntaxNode syntax, Conversion conversion, BoundExpression right) + { + Debug.Assert(conversion.Kind == ConversionKind.Deconstruction); + + // We only need to visit the right side when deconstruction uses a Deconstruct() method call + // (when !DeconstructionInfo.IsDefault), not when the right side is a tuple, because ref structs + // cannot be used as tuple type arguments. + if (conversion.DeconstructionInfo.IsDefault) + { + return; + } + + var invocation = conversion.DeconstructionInfo.Invocation as BoundCall; + if (invocation is null) + { + return; + } + + var deconstructMethod = invocation.Method; + if (deconstructMethod is null) + { + return; + } + + var placeholders = ArrayBuilder<(BoundValuePlaceholderBase, uint)>.GetInstance(); + placeholders.Add((conversion.DeconstructionInfo.InputPlaceholder, GetValEscape(right, _localScopeDepth))); + + var parameters = deconstructMethod.Parameters; + int n = variables.Count; + int offset = invocation.InvokedAsExtensionMethod ? 1 : 0; + Debug.Assert(parameters.Length - offset == n); + + for (int i = 0; i < n; i++) + { + var variable = variables[i]; + var nestedVariables = variable.NestedVariables; + var arg = (BoundDeconstructValuePlaceholder)invocation.Arguments[i + offset]; + uint valEscape = nestedVariables is null + ? GetValEscape(variable.Expression, _localScopeDepth) + : _localScopeDepth; + placeholders.Add((arg, valEscape)); + } + + using var _ = new PlaceholderRegion(this, placeholders); + + CheckInvocationArgMixing( + syntax, + deconstructMethod, + invocation.ReceiverOpt, + parameters, + invocation.Arguments, + invocation.ArgumentRefKindsOpt, + invocation.ArgsToParamsOpt, + _localScopeDepth, + _diagnostics); + + for (int i = 0; i < n; i++) + { + var variable = variables[i]; + var nestedVariables = variable.NestedVariables; + if (nestedVariables != null) + { + var (placeholder, placeholderConversion) = conversion.DeconstructConversionInfo[i]; + var underlyingConversion = BoundNode.GetConversion(placeholderConversion, placeholder); + VisitDeconstructionArguments(nestedVariables, syntax, underlyingConversion, right: invocation.Arguments[i + offset]); + } + } + } + + private readonly struct DeconstructionVariable + { + internal readonly BoundExpression Expression; + internal readonly uint ValEscape; + internal readonly ArrayBuilder? NestedVariables; + + internal DeconstructionVariable(BoundExpression expression, uint valEscape, ArrayBuilder? nestedVariables) + { + Expression = expression; + ValEscape = valEscape; + NestedVariables = nestedVariables; + } + } + + private ArrayBuilder GetDeconstructionAssignmentVariables(BoundTupleExpression tuple) + { + var arguments = tuple.Arguments; + var builder = ArrayBuilder.GetInstance(arguments.Length); + foreach (var arg in arguments) + { + builder.Add(getDeconstructionAssignmentVariable(arg)); + } + return builder; + + DeconstructionVariable getDeconstructionAssignmentVariable(BoundExpression expr) + { + return expr is BoundTupleExpression tuple + ? new DeconstructionVariable(expr, valEscape: uint.MaxValue, GetDeconstructionAssignmentVariables(tuple)) + : new DeconstructionVariable(expr, GetValEscape(expr, _localScopeDepth), null); + } + } + + private static ImmutableArray GetDeconstructionRightParts(BoundExpression expr) + { + switch (expr) + { + case BoundTupleExpression tuple: + return tuple.Arguments; + case BoundConversion conv: + switch (conv.ConversionKind) + { + case ConversionKind.Identity: + case ConversionKind.ImplicitTupleLiteral: + return GetDeconstructionRightParts(conv.Operand); + } + break; + } + + throw ExceptionUtilities.Unreachable(); + } + + public override BoundNode? VisitForEachStatement(BoundForEachStatement node) + { + uint collectionEscape = GetValEscape(node.Expression, _localScopeDepth); + using var _ = new LocalScope(this, ImmutableArray.Empty); + + foreach (var local in node.IterationVariables) + { + AddLocalScopes(local, refEscapeScope: local.RefKind == RefKind.None ? _localScopeDepth : collectionEscape, valEscapeScope: collectionEscape); + } + + var placeholders = ArrayBuilder<(BoundValuePlaceholderBase, uint)>.GetInstance(); + if (node.DeconstructionOpt?.TargetPlaceholder is { } targetPlaceholder) + { + placeholders.Add((targetPlaceholder, collectionEscape)); + } + if (node.AwaitOpt is { } awaitableInfo) + { + GetAwaitableInstancePlaceholders(placeholders, awaitableInfo, collectionEscape); + } + + using var region = new PlaceholderRegion(this, placeholders); + base.VisitForEachStatement(node); + + foreach (var local in node.IterationVariables) + { + RemoveLocalScopes(local); + } + + return null; + } + + private static void Error(BindingDiagnosticBag diagnostics, ErrorCode code, SyntaxNodeOrToken syntax, params object[] args) + { + var location = syntax.GetLocation(); + RoslynDebug.Assert(location is object); + Error(diagnostics, code, location, args); + } + + private static void Error(BindingDiagnosticBag diagnostics, ErrorCode code, Location location, params object[] args) + { + diagnostics.Add(new CSDiagnostic(new CSDiagnosticInfo(code, args), location)); + } + } +} diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversions.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversions.cs index 838d50d7f630c..91deb69e37352 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversions.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Immutable; using System.Diagnostics; +using System.Linq; using Microsoft.CodeAnalysis.CSharp.Symbols; namespace Microsoft.CodeAnalysis.CSharp @@ -33,7 +34,6 @@ protected override ConversionsBase CreateInstance(int currentRecursionDepth) #nullable enable protected override CSharpCompilation Compilation { get { return _binder.Compilation; } } -#nullable disable protected override ConversionsBase WithNullabilityCore(bool includeNullability) { @@ -57,13 +57,48 @@ public override Conversion GetMethodGroupDelegateConversion(BoundMethodGroup sou Debug.Assert(methodSymbol == ((NamedTypeSymbol)destination).DelegateInvokeMethod); - // If synthesizing a delegate with `params` array, check that `ParamArrayAttribute` is available. - if (methodSymbol.OriginalDefinition is SynthesizedDelegateInvokeMethod { Parameters: [.., { IsParams: true }] }) + if (methodSymbol.OriginalDefinition is SynthesizedDelegateInvokeMethod invoke) { - Binder.GetWellKnownTypeMember(Compilation, - WellKnownMember.System_ParamArrayAttribute__ctor, - out var memberUseSiteInfo); - useSiteInfo.Add(memberUseSiteInfo); + // If synthesizing a delegate with `params` array, check that `ParamArrayAttribute` is available. + if (invoke.IsParams()) + { + Binder.AddUseSiteDiagnosticForSynthesizedAttribute( + Compilation, + WellKnownMember.System_ParamArrayAttribute__ctor, + ref useSiteInfo); + } + + // If synthesizing a delegate with `decimal`/`DateTime` default value, + // check that the corresponding `*ConstantAttribute` is available. + foreach (var p in invoke.Parameters) + { + var defaultValue = p.ExplicitDefaultConstantValue; + if (defaultValue != ConstantValue.NotAvailable) + { + WellKnownMember? member = defaultValue.SpecialType switch + { + SpecialType.System_Decimal => WellKnownMember.System_Runtime_CompilerServices_DecimalConstantAttribute__ctor, + SpecialType.System_DateTime => WellKnownMember.System_Runtime_CompilerServices_DateTimeConstantAttribute__ctor, + _ => null + }; + if (member != null) + { + Binder.AddUseSiteDiagnosticForSynthesizedAttribute( + Compilation, + member.GetValueOrDefault(), + ref useSiteInfo); + } + } + } + + // If synthesizing a delegate with an [UnscopedRef] parameter, check the attribute is available. + if (invoke.Parameters.Any(p => p.HasUnscopedRefAttribute)) + { + Binder.AddUseSiteDiagnosticForSynthesizedAttribute( + Compilation, + WellKnownMember.System_Diagnostics_CodeAnalysis_UnscopedRefAttribute__ctor, + ref useSiteInfo); + } } var resolution = ResolveDelegateOrFunctionPointerMethodGroup(_binder, source, methodSymbol, isFunctionPointer, callingConventionInfo, ref useSiteInfo); @@ -73,6 +108,7 @@ public override Conversion GetMethodGroupDelegateConversion(BoundMethodGroup sou resolution.Free(); return conversion; } +#nullable disable public override Conversion GetMethodGroupFunctionPointerConversion(BoundMethodGroup source, FunctionPointerTypeSymbol destination, ref CompoundUseSiteInfo useSiteInfo) { diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs index 2e70a14ceb381..ea9a3976650c8 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs @@ -1273,7 +1273,7 @@ private Conversion ClassifyExplicitTupleLiteralConversion(BoundTupleLiteral sour internal static bool HasImplicitConstantExpressionConversion(BoundExpression source, TypeSymbol destination) { - var constantValue = source.ConstantValue; + var constantValue = source.ConstantValueOpt; if (constantValue == null || (object)source.Type == null) { @@ -1382,7 +1382,7 @@ private static bool HasImplicitEnumerationConversion(BoundExpression source, Typ return false; } - var sourceConstantValue = source.ConstantValue; + var sourceConstantValue = source.ConstantValueOpt; return sourceConstantValue != null && source.Type is object && IsNumericType(source.Type) && diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/Operators/BinaryOperatorEasyOut.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Operators/BinaryOperatorEasyOut.cs index 7e37deb552c5a..0ec693b8156ff 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/Operators/BinaryOperatorEasyOut.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/Operators/BinaryOperatorEasyOut.cs @@ -337,7 +337,7 @@ private static bool PossiblyUnusualConstantOperation(BoundExpression left, Bound // int, both have to be bool, or both have to be string. Otherwise // we skip the easy out and go for the slow path. - if (left.ConstantValue == null && right.ConstantValue == null) + if (left.ConstantValueOpt == null && right.ConstantValueOpt == null) { // Neither is constant. Go for the easy out. return false; diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs index 2b4e81830f0ae..0c694247f1f9e 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs @@ -2456,7 +2456,7 @@ private BetterResult BetterConversionFromExpression(BoundExpression node, TypeSy // choice after we received customer reports of problems in the space. // https://github.com/dotnet/roslyn/issues/55345 if (_binder.Compilation.IsFeatureEnabled(MessageID.IDS_FeatureImprovedInterpolatedStrings) && - node is BoundUnconvertedInterpolatedString { ConstantValueOpt: null } or BoundBinaryOperator { IsUnconvertedInterpolatedStringAddition: true, ConstantValue: null }) + node is BoundUnconvertedInterpolatedString { ConstantValueOpt: null } or BoundBinaryOperator { IsUnconvertedInterpolatedStringAddition: true, ConstantValueOpt: null }) { switch ((conv1.Kind, conv2.Kind)) { diff --git a/src/Compilers/CSharp/Portable/Binder/SwitchBinder.cs b/src/Compilers/CSharp/Portable/Binder/SwitchBinder.cs index 015e20d3a49cc..e2b4a95824146 100644 --- a/src/Compilers/CSharp/Portable/Binder/SwitchBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/SwitchBinder.cs @@ -46,8 +46,6 @@ protected BoundExpression SwitchGoverningExpression protected TypeSymbol SwitchGoverningType => SwitchGoverningExpression.Type; - protected uint SwitchGoverningValEscape => GetValEscape(SwitchGoverningExpression, LocalScopeDepth); - protected BindingDiagnosticBag SwitchGoverningDiagnostics { get @@ -222,7 +220,7 @@ private void BuildSwitchLabels(SyntaxList labelsSyntax, Binde // bind the pattern, to cause its pattern variables to be inferred if necessary var matchLabel = (CasePatternSwitchLabelSyntax)labelSyntax; _ = sectionBinder.BindPattern( - matchLabel.Pattern, SwitchGoverningType, SwitchGoverningValEscape, permitDesignations: true, labelSyntax.HasErrors, tempDiagnosticBag); + matchLabel.Pattern, SwitchGoverningType, permitDesignations: true, labelSyntax.HasErrors, tempDiagnosticBag); break; default: diff --git a/src/Compilers/CSharp/Portable/Binder/SwitchBinder_Patterns.cs b/src/Compilers/CSharp/Portable/Binder/SwitchBinder_Patterns.cs index a6c0217c40cf0..a70f367e3446b 100644 --- a/src/Compilers/CSharp/Portable/Binder/SwitchBinder_Patterns.cs +++ b/src/Compilers/CSharp/Portable/Binder/SwitchBinder_Patterns.cs @@ -270,7 +270,7 @@ private BoundSwitchLabel BindSwitchSectionLabel( MessageID.IDS_FeaturePatternMatching.CheckFeatureAvailability(diagnostics, node, node.Keyword.GetLocation()); BoundPattern pattern = sectionBinder.BindPattern( - matchLabelSyntax.Pattern, SwitchGoverningType, SwitchGoverningValEscape, permitDesignations: true, node.HasErrors, diagnostics); + matchLabelSyntax.Pattern, SwitchGoverningType, permitDesignations: true, node.HasErrors, diagnostics); if (matchLabelSyntax.Pattern is ConstantPatternSyntax p) reportIfConstantNamedUnderscore(pattern, p.Expression); diff --git a/src/Compilers/CSharp/Portable/Binder/SwitchExpressionArmBinder.cs b/src/Compilers/CSharp/Portable/Binder/SwitchExpressionArmBinder.cs index 4e7400bc67a43..62406a5a774bf 100644 --- a/src/Compilers/CSharp/Portable/Binder/SwitchExpressionArmBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/SwitchExpressionArmBinder.cs @@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.CSharp /// Binder for one of the arms of a switch expression. For example, in the one-armed switch expression /// "e switch { p when c => v }", this could be the binder for the arm "p when c => v". /// - internal class SwitchExpressionArmBinder : Binder + internal sealed class SwitchExpressionArmBinder : Binder { private readonly SwitchExpressionArmSyntax _arm; private readonly ExpressionVariableBinder _armScopeBinder; @@ -29,17 +29,17 @@ public SwitchExpressionArmBinder(SwitchExpressionArmSyntax arm, ExpressionVariab internal BoundSwitchExpressionArm BindSwitchExpressionArm(SwitchExpressionArmSyntax node, BindingDiagnosticBag diagnostics) { Debug.Assert(node == _arm); - (TypeSymbol inputType, uint valEscape) = _switchExpressionBinder.GetInputTypeAndValEscape(); - return BindSwitchExpressionArm(node, inputType, valEscape, diagnostics); + TypeSymbol inputType = _switchExpressionBinder.GetInputType(); + return BindSwitchExpressionArm(node, inputType, diagnostics); } - internal override BoundSwitchExpressionArm BindSwitchExpressionArm(SwitchExpressionArmSyntax node, TypeSymbol switchGoverningType, uint switchGoverningValEscape, BindingDiagnosticBag diagnostics) + internal override BoundSwitchExpressionArm BindSwitchExpressionArm(SwitchExpressionArmSyntax node, TypeSymbol switchGoverningType, BindingDiagnosticBag diagnostics) { Debug.Assert(node == _arm); Binder armBinder = this.GetRequiredBinder(node); bool hasErrors = switchGoverningType.IsErrorType(); ImmutableArray locals = _armScopeBinder.Locals; - BoundPattern pattern = armBinder.BindPattern(node.Pattern, switchGoverningType, switchGoverningValEscape, permitDesignations: true, hasErrors, diagnostics); + BoundPattern pattern = armBinder.BindPattern(node.Pattern, switchGoverningType, permitDesignations: true, hasErrors, diagnostics); BoundExpression? whenClause = node.WhenClause != null ? armBinder.BindBooleanExpression(node.WhenClause.Condition, diagnostics) : null; diff --git a/src/Compilers/CSharp/Portable/Binder/SwitchExpressionBinder.cs b/src/Compilers/CSharp/Portable/Binder/SwitchExpressionBinder.cs index 54479b444ccf7..463109a589e10 100644 --- a/src/Compilers/CSharp/Portable/Binder/SwitchExpressionBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/SwitchExpressionBinder.cs @@ -170,23 +170,23 @@ ImmutableArray nonNullSuccessors(BoundDecisionDagNode n) private ImmutableArray BindSwitchExpressionArms(SwitchExpressionSyntax node, Binder originalBinder, BoundExpression inputExpression, BindingDiagnosticBag diagnostics) { var builder = ArrayBuilder.GetInstance(); - (TypeSymbol inputType, uint valEscape) = GetInputTypeAndValEscape(inputExpression); + TypeSymbol inputType = GetInputType(inputExpression); foreach (var arm in node.Arms) { var armBinder = originalBinder.GetRequiredBinder(arm); Debug.Assert(inputExpression.Type is not null); - var boundArm = armBinder.BindSwitchExpressionArm(arm, inputType, valEscape, diagnostics); + var boundArm = armBinder.BindSwitchExpressionArm(arm, inputType, diagnostics); builder.Add(boundArm); } return builder.ToImmutableAndFree(); } - internal (TypeSymbol GoverningType, uint GoverningValEscape) GetInputTypeAndValEscape(BoundExpression? inputExpression = null) + internal TypeSymbol GetInputType(BoundExpression? inputExpression = null) { inputExpression ??= BindSwitchGoverningExpression(BindingDiagnosticBag.Discarded); Debug.Assert(inputExpression.Type is not null); - return (inputExpression.Type, GetValEscape(inputExpression, LocalScopeDepth)); + return inputExpression.Type; } private BoundExpression BindSwitchGoverningExpression(BindingDiagnosticBag diagnostics) diff --git a/src/Compilers/CSharp/Portable/Binder/UsingStatementBinder.cs b/src/Compilers/CSharp/Portable/Binder/UsingStatementBinder.cs index fff7a1825be72..e3b5721d490ec 100644 --- a/src/Compilers/CSharp/Portable/Binder/UsingStatementBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/UsingStatementBinder.cs @@ -150,7 +150,7 @@ internal static BoundStatement BindUsingStatementOrDeclarationFromParts(SyntaxNo else { hasErrors |= ReportUseSite(awaitableTypeOpt, diagnostics, awaitKeyword); - var placeholder = new BoundAwaitableValuePlaceholder(syntax, valEscape: originalBinder.LocalScopeDepth, awaitableTypeOpt).MakeCompilerGenerated(); + var placeholder = new BoundAwaitableValuePlaceholder(syntax, awaitableTypeOpt).MakeCompilerGenerated(); awaitOpt = originalBinder.BindAwaitInfo(placeholder, syntax, diagnostics, ref hasErrors); } } diff --git a/src/Compilers/CSharp/Portable/Binder/WithExternAliasesBinder.cs b/src/Compilers/CSharp/Portable/Binder/WithExternAliasesBinder.cs index 9e096bbe4529c..1a0aeb05d04de 100644 --- a/src/Compilers/CSharp/Portable/Binder/WithExternAliasesBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/WithExternAliasesBinder.cs @@ -69,8 +69,6 @@ internal override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo resu return null; } - internal sealed override uint LocalScopeDepth => Binder.CallingMethodScope; - internal static WithExternAliasesBinder Create(SourceNamespaceSymbol declaringSymbol, CSharpSyntaxNode declarationSyntax, Binder next) { return new FromSyntax(declaringSymbol, declarationSyntax, next); diff --git a/src/Compilers/CSharp/Portable/Binder/WithLambdaParametersBinder.cs b/src/Compilers/CSharp/Portable/Binder/WithLambdaParametersBinder.cs index 05400c70996e4..c31a0543f343a 100644 --- a/src/Compilers/CSharp/Portable/Binder/WithLambdaParametersBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/WithLambdaParametersBinder.cs @@ -176,7 +176,5 @@ internal override ImmutableArray GetDeclaredLocalFunctionsF { throw ExceptionUtilities.Unreachable(); } - - internal override uint LocalScopeDepth => Binder.CurrentMethodScope; } } diff --git a/src/Compilers/CSharp/Portable/Binder/WithUsingNamespacesAndTypesBinder.cs b/src/Compilers/CSharp/Portable/Binder/WithUsingNamespacesAndTypesBinder.cs index 65ec9dfd2d5cf..6dca9506b42e6 100644 --- a/src/Compilers/CSharp/Portable/Binder/WithUsingNamespacesAndTypesBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/WithUsingNamespacesAndTypesBinder.cs @@ -225,8 +225,6 @@ internal override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo resu return null; } - internal override uint LocalScopeDepth => Binder.CallingMethodScope; - internal override ImportChain? ImportChain { get diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundDecisionDag.cs b/src/Compilers/CSharp/Portable/BoundTree/BoundDecisionDag.cs index 8292b3878d0da..eec713ae6fbbc 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundDecisionDag.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundDecisionDag.cs @@ -137,13 +137,13 @@ public static BoundDecisionDagNode TrivialReplacement(BoundDecisionDagNode dag, /// public BoundDecisionDag SimplifyDecisionDagIfConstantInput(BoundExpression input) { - if (input.ConstantValue == null) + if (input.ConstantValueOpt == null) { return this; } else { - ConstantValue inputConstant = input.ConstantValue; + ConstantValue inputConstant = input.ConstantValueOpt; return Rewrite(makeReplacement); // Make a replacement for a given node, using the precomputed replacements for its successors. diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundDiscardExpression.cs b/src/Compilers/CSharp/Portable/BoundTree/BoundDiscardExpression.cs index 787b7621fe4e8..10fd67b7c23ef 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundDiscardExpression.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundDiscardExpression.cs @@ -12,7 +12,7 @@ internal partial class BoundDiscardExpression public BoundExpression SetInferredTypeWithAnnotations(TypeWithAnnotations type) { Debug.Assert(Type is null && type.HasType); - return this.Update(ValEscape, type.Type); + return this.Update(type.Type); } public BoundDiscardExpression FailInference(Binder binder, BindingDiagnosticBag? diagnosticsOpt) @@ -21,7 +21,7 @@ public BoundDiscardExpression FailInference(Binder binder, BindingDiagnosticBag? { Binder.Error(diagnosticsOpt, ErrorCode.ERR_DiscardTypeInferenceFailed, this.Syntax); } - return this.Update(ValEscape, binder.CreateErrorType("var")); + return this.Update(binder.CreateErrorType("var")); } public override Symbol ExpressionSymbol diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundExpression.cs b/src/Compilers/CSharp/Portable/BoundTree/BoundExpression.cs index ebac343dbfd75..320953b548abe 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundExpression.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundExpression.cs @@ -78,7 +78,7 @@ internal bool NeedsToBeConverted() } } - public virtual ConstantValue? ConstantValue + public virtual ConstantValue? ConstantValueOpt { get { @@ -211,11 +211,11 @@ internal partial class BoundThisReference internal partial class BoundPassByCopy { - public override ConstantValue? ConstantValue + public override ConstantValue? ConstantValueOpt { get { - Debug.Assert(Expression.ConstantValue == null); + Debug.Assert(Expression.ConstantValueOpt == null); return null; } } @@ -270,11 +270,6 @@ public override Symbol ExpressionSymbol internal partial class BoundLocal { - public override ConstantValue? ConstantValue - { - get { return this.ConstantValueOpt; } - } - public override Symbol ExpressionSymbol { get { return this.LocalSymbol; } @@ -293,11 +288,6 @@ public BoundLocal Update(LocalSymbol localSymbol, ConstantValue? constantValueOp internal partial class BoundFieldAccess { - public override ConstantValue? ConstantValue - { - get { return this.ConstantValueOpt; } - } - public override Symbol? ExpressionSymbol { get { return this.FieldSymbol; } @@ -362,7 +352,7 @@ public override Symbol ExpressionSymbol internal partial class BoundBinaryOperator { - public override ConstantValue? ConstantValue => Data?.ConstantValue; + public override ConstantValue? ConstantValueOpt => Data?.ConstantValue; public override Symbol? ExpressionSymbol => this.Method; @@ -377,14 +367,6 @@ internal partial class BoundBinaryOperator internal ImmutableArray OriginalUserDefinedOperatorsOpt => Data?.OriginalUserDefinedOperatorsOpt ?? default(ImmutableArray); } - internal partial class BoundInterpolatedStringBase - { - public sealed override ConstantValue? ConstantValue - { - get { return this.ConstantValueOpt; } - } - } - internal partial class BoundUserDefinedConditionalLogicalOperator { public override Symbol ExpressionSymbol @@ -395,11 +377,6 @@ public override Symbol ExpressionSymbol internal partial class BoundUnaryOperator { - public override ConstantValue? ConstantValue - { - get { return this.ConstantValueOpt; } - } - public override Symbol? ExpressionSymbol { get { return this.MethodOpt; } @@ -422,21 +399,8 @@ public override Symbol? ExpressionSymbol } } - internal partial class BoundLiteral - { - public override ConstantValue? ConstantValue - { - get { return this.ConstantValueOpt; } - } - } - internal partial class BoundConversion { - public override ConstantValue? ConstantValue - { - get { return this.ConstantValueOpt; } - } - public ConversionKind ConversionKind { get { return this.Conversion.Kind; } @@ -464,7 +428,7 @@ public override bool SuppressVirtualCalls public BoundConversion UpdateOperand(BoundExpression operand) { - return this.Update(operand: operand, this.Conversion, this.IsBaseConversion, this.Checked, this.ExplicitCastInCode, this.ConstantValue, this.ConversionGroupOpt, this.OriginalUserDefinedConversionsOpt, this.Type); + return this.Update(operand: operand, this.Conversion, this.IsBaseConversion, this.Checked, this.ExplicitCastInCode, this.ConstantValueOpt, this.ConversionGroupOpt, this.OriginalUserDefinedConversionsOpt, this.Type); } /// @@ -500,11 +464,6 @@ internal bool ConversionHasSideEffects() internal partial class BoundObjectCreationExpression { - public override ConstantValue? ConstantValue - { - get { return this.ConstantValueOpt; } - } - public override Symbol ExpressionSymbol { get { return this.Constructor; } @@ -567,7 +526,7 @@ public override Symbol? ExpressionSymbol internal partial class BoundDefaultLiteral { - public override ConstantValue? ConstantValue + public override ConstantValue? ConstantValueOpt { get { return null; } } @@ -575,14 +534,6 @@ public override ConstantValue? ConstantValue internal partial class BoundConditionalOperator { - public override ConstantValue? ConstantValue - { - get - { - return this.ConstantValueOpt; - } - } - public bool IsDynamic { get @@ -594,28 +545,6 @@ public bool IsDynamic } } - internal partial class BoundUnconvertedConditionalOperator - { - public override ConstantValue? ConstantValue - { - get - { - return this.ConstantValueOpt; - } - } - } - - internal partial class BoundSizeOfOperator - { - public override ConstantValue? ConstantValue - { - get - { - return this.ConstantValueOpt; - } - } - } - internal partial class BoundRangeVariable { public override Symbol ExpressionSymbol @@ -668,17 +597,6 @@ public override bool SuppressVirtualCalls } } - internal partial class BoundNameOfOperator - { - public override ConstantValue ConstantValue - { - get - { - return this.ConstantValueOpt; - } - } - } - // NOTE: this type exists in order to hide the presence of {Value,Type}Expression inside of a // BoundTypeOrValueExpression from the bound tree generator, which would otherwise generate // a constructor that may spuriously set hasErrors to true if either field had errors. diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundExpressionExtensions.cs b/src/Compilers/CSharp/Portable/BoundTree/BoundExpressionExtensions.cs index e5c6a8c3d8991..d4627c5797403 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundExpressionExtensions.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundExpressionExtensions.cs @@ -62,7 +62,7 @@ public static RefKind GetRefKind(this BoundExpression node) public static bool IsLiteralNull(this BoundExpression node) { - return node is { Kind: BoundKind.Literal, ConstantValue: { Discriminator: ConstantValueTypeDiscriminator.Null } }; + return node is { Kind: BoundKind.Literal, ConstantValueOpt: { Discriminator: ConstantValueTypeDiscriminator.Null } }; } public static bool IsLiteralDefault(this BoundExpression node) @@ -93,7 +93,7 @@ public static bool IsDefaultValue(this BoundExpression node) return true; } - var constValue = node.ConstantValue; + var constValue = node.ConstantValueOpt; if (constValue != null) { return constValue.IsDefaultValue; @@ -268,5 +268,16 @@ internal static bool IsExpressionOfComImportType([NotNullWhen(true)] this BoundE TypeSymbol? receiverType = expressionOpt.Type; return receiverType is NamedTypeSymbol { Kind: SymbolKind.NamedType, IsComImport: true }; } + + internal static bool IsDiscardExpression(this BoundExpression expr) + { + return expr switch + { + BoundDiscardExpression => true, + OutDeconstructVarPendingInference { IsDiscardExpression: true } => true, + BoundDeconstructValuePlaceholder { IsDiscardExpression: true } => true, + _ => false + }; + } } } diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundIsPatternExpression.cs b/src/Compilers/CSharp/Portable/BoundTree/BoundIsPatternExpression.cs index a5500883aa3c0..bab83be24fbf5 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundIsPatternExpression.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundIsPatternExpression.cs @@ -13,11 +13,13 @@ public BoundDecisionDag GetDecisionDagForLowering(CSharpCompilation compilation) BoundDecisionDag decisionDag = this.ReachabilityDecisionDag; if (decisionDag.ContainsAnySynthesizedNodes()) { + bool negated = this.Pattern.IsNegated(out var innerPattern); + Debug.Assert(negated == this.IsNegated); decisionDag = DecisionDagBuilder.CreateDecisionDagForIsPattern( compilation, this.Syntax, this.Expression, - this.Pattern, + innerPattern, this.WhenTrueLabel, this.WhenFalseLabel, BindingDiagnosticBag.Discarded, diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundNode_Source.cs b/src/Compilers/CSharp/Portable/BoundTree/BoundNode_Source.cs index 849b0bffa83ea..fc16beb0bd922 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundNode_Source.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundNode_Source.cs @@ -220,13 +220,13 @@ void appendSourceCore(BoundNode node, int indent, Dictionary - + - - - @@ -174,7 +171,6 @@ - @@ -339,7 +335,7 @@ - + @@ -635,7 +631,7 @@ - + @@ -647,7 +643,7 @@ - + @@ -780,7 +776,7 @@ - + @@ -812,7 +808,7 @@ - + @@ -825,7 +821,7 @@ - + @@ -1707,6 +1704,7 @@ matching Id that are integers unique for the containing method body. --> + @@ -1716,8 +1714,8 @@ - @@ -1727,6 +1725,16 @@ + + + + + + + - + @@ -2195,7 +2203,7 @@ from the literal parts of the input. The odd numbered positions are the string inserts. If the interpolated string has been bound using the builder pattern, literals are replaced with calls. --> - + @@ -2215,7 +2223,6 @@ - @@ -2363,7 +2370,6 @@ is null before type inference, and it is replaced by a BoundDiscardExpression with a non-null type after inference. --> - @@ -2384,13 +2390,13 @@ - + - + diff --git a/src/Compilers/CSharp/Portable/BoundTree/Constructors.cs b/src/Compilers/CSharp/Portable/BoundTree/Constructors.cs index 51b200b121f41..fb92093a9846f 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/Constructors.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/Constructors.cs @@ -595,7 +595,7 @@ public BoundGotoStatement(SyntaxNode syntax, LabelSymbol label, bool hasErrors = internal partial class BoundBlock { - public BoundBlock(SyntaxNode syntax, ImmutableArray locals, ImmutableArray statements, bool hasErrors = false) : this(syntax, locals, ImmutableArray.Empty, statements, hasErrors) + public BoundBlock(SyntaxNode syntax, ImmutableArray locals, ImmutableArray statements, bool hasErrors = false) : this(syntax, locals, ImmutableArray.Empty, hasUnsafeModifier: false, statements, hasErrors) { } @@ -622,8 +622,6 @@ public BoundDefaultExpression(SyntaxNode syntax, TypeSymbol type, bool hasErrors : this(syntax, targetType: null, type.GetDefaultValue(), type, hasErrors) { } - - public override ConstantValue? ConstantValue => ConstantValueOpt; } internal partial class BoundTryStatement diff --git a/src/Compilers/CSharp/Portable/BoundTree/Formatting.cs b/src/Compilers/CSharp/Portable/BoundTree/Formatting.cs index f801e1d21d2cf..70bf08291164a 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/Formatting.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/Formatting.cs @@ -36,7 +36,7 @@ internal sealed partial class BoundLiteral { public override object Display { - get { return ConstantValue?.IsNull == true ? MessageID.IDS_NULL.Localize() : base.Display; } + get { return ConstantValueOpt?.IsNull == true ? MessageID.IDS_NULL.Localize() : base.Display; } } } diff --git a/src/Compilers/CSharp/Portable/BoundTree/InterpolatedStringHandlerData.cs b/src/Compilers/CSharp/Portable/BoundTree/InterpolatedStringHandlerData.cs index 2d4ed85c5b7a9..4bd5f83599a20 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/InterpolatedStringHandlerData.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/InterpolatedStringHandlerData.cs @@ -14,11 +14,6 @@ internal readonly struct InterpolatedStringHandlerData public readonly BoundExpression Construction; public readonly bool UsesBoolReturns; /// - /// The scope of the expression that contained the interpolated string during initial binding. This is used to determine the SafeToEscape rules - /// for the builder during lowering. - /// - public readonly uint ScopeOfContainingExpression; - /// /// The placeholders that are used for . /// public readonly ImmutableArray ArgumentPlaceholders; @@ -35,7 +30,6 @@ public InterpolatedStringHandlerData( TypeSymbol builderType, BoundExpression construction, bool usesBoolReturns, - uint scopeOfContainingExpression, ImmutableArray placeholders, ImmutableArray> positionInfo, BoundInterpolatedStringHandlerPlaceholder receiverPlaceholder) @@ -48,7 +42,6 @@ public InterpolatedStringHandlerData( BuilderType = builderType; Construction = construction; UsesBoolReturns = usesBoolReturns; - ScopeOfContainingExpression = scopeOfContainingExpression; ArgumentPlaceholders = placeholders; PositionInfo = positionInfo; ReceiverPlaceholder = receiverPlaceholder; diff --git a/src/Compilers/CSharp/Portable/BoundTree/OutDeconstructVarPendingInference.cs b/src/Compilers/CSharp/Portable/BoundTree/OutDeconstructVarPendingInference.cs index 3144b9e6d385b..0cf0546f9c14d 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/OutDeconstructVarPendingInference.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/OutDeconstructVarPendingInference.cs @@ -15,7 +15,7 @@ public BoundDeconstructValuePlaceholder SetInferredTypeWithAnnotations(TypeWithA { Debug.Assert(Placeholder is null); - Placeholder = new BoundDeconstructValuePlaceholder(this.Syntax, variableSymbol: VariableSymbol, ValEscape, type.Type, hasErrors: this.HasErrors || !success); + Placeholder = new BoundDeconstructValuePlaceholder(this.Syntax, variableSymbol: VariableSymbol, isDiscardExpression: IsDiscardExpression, type.Type, hasErrors: this.HasErrors || !success); return Placeholder; } diff --git a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs index aa856e1b8b7a2..97e6044c57187 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs @@ -381,7 +381,7 @@ public static UnboundLambda Create( TypeWithAnnotations returnType, ImmutableArray> parameterAttributes, ImmutableArray refKinds, - ImmutableArray declaredScopes, + ImmutableArray declaredScopes, ImmutableArray types, ImmutableArray names, ImmutableArray discardsOpt, @@ -456,7 +456,7 @@ public TypeWithAnnotations InferReturnType(ConversionsBase conversions, NamedTyp => BindForReturnTypeInference(delegateType).GetInferredReturnType(conversions, _nullableState, ref useSiteInfo, out inferredFromFunctionType); public RefKind RefKind(int index) { return Data.RefKind(index); } - public DeclarationScope DeclaredScope(int index) { return Data.DeclaredScope(index); } + public ScopedKind DeclaredScope(int index) { return Data.DeclaredScope(index); } public void GenerateAnonymousFunctionConversionError(BindingDiagnosticBag diagnostics, TypeSymbol targetType) { Data.GenerateAnonymousFunctionConversionError(diagnostics, targetType); } public bool GenerateSummaryErrors(BindingDiagnosticBag diagnostics) { return Data.GenerateSummaryErrors(diagnostics); } public bool IsAsync { get { return Data.IsAsync; } } @@ -539,7 +539,7 @@ internal UnboundLambdaState WithCaching(bool includeCache) public abstract Location ParameterLocation(int index); public abstract TypeWithAnnotations ParameterTypeWithAnnotations(int index); public abstract RefKind RefKind(int index); - public abstract DeclarationScope DeclaredScope(int index); + public abstract ScopedKind DeclaredScope(int index); public abstract ParameterSyntax? ParameterSyntax(int i); protected abstract BoundBlock BindLambdaBody(LambdaSymbol lambdaSymbol, Binder lambdaBodyBinder, BindingDiagnosticBag diagnostics); @@ -612,10 +612,10 @@ private static TypeWithAnnotations DelegateReturnTypeWithAnnotations(MethodSymbo return invokeMethod.ReturnTypeWithAnnotations; } - internal (ImmutableArray, ArrayBuilder, ImmutableArray, bool) CollectParameterProperties() + internal (ImmutableArray, ArrayBuilder, ImmutableArray, bool) CollectParameterProperties() { var parameterRefKindsBuilder = ArrayBuilder.GetInstance(ParameterCount); - var parameterScopesBuilder = ArrayBuilder.GetInstance(ParameterCount); + var parameterScopesBuilder = ArrayBuilder.GetInstance(ParameterCount); var parameterTypesBuilder = ArrayBuilder.GetInstance(ParameterCount); bool getEffectiveScopeFromSymbol = false; @@ -624,10 +624,10 @@ private static TypeWithAnnotations DelegateReturnTypeWithAnnotations(MethodSymbo var refKind = RefKind(i); var scope = DeclaredScope(i); var type = ParameterTypeWithAnnotations(i); - if (scope == DeclarationScope.Unscoped && + if (scope == ScopedKind.None && ParameterHelpers.IsRefScopedByDefault(Binder.UseUpdatedEscapeRules, refKind)) { - scope = DeclarationScope.RefScoped; + scope = ScopedKind.ScopedRef; if (_unboundLambda.ParameterAttributes(i).Any()) { getEffectiveScopeFromSymbol = true; @@ -691,7 +691,7 @@ private static TypeWithAnnotations DelegateReturnTypeWithAnnotations(MethodSymbo { for (int i = 0; i < ParameterCount; i++) { - if (DeclaredScope(i) == DeclarationScope.Unscoped && parameterScopesBuilder[i] == DeclarationScope.RefScoped && _unboundLambda.ParameterAttributes(i).Any()) + if (DeclaredScope(i) == ScopedKind.None && parameterScopesBuilder[i] == ScopedKind.ScopedRef && _unboundLambda.ParameterAttributes(i).Any()) { Debug.Assert(getEffectiveScopeFromSymbol); parameterScopesBuilder[i] = lambdaSymbol.Parameters[i].EffectiveScope; @@ -713,6 +713,7 @@ private static TypeWithAnnotations DelegateReturnTypeWithAnnotations(MethodSymbo _unboundLambda.Syntax, lambdaSymbol, parameterScopesBuilder.ToImmutableAndFree(), + lambdaSymbol.Parameters.SelectAsArray(p => p.HasUnscopedRefAttribute), returnRefKind, returnType); } @@ -1377,7 +1378,7 @@ internal sealed class PlainUnboundLambdaState : UnboundLambdaState private readonly ImmutableArray _parameterIsDiscardOpt; private readonly ImmutableArray _parameterTypesWithAnnotations; private readonly ImmutableArray _parameterRefKinds; - private readonly ImmutableArray _parameterDeclaredScopes; + private readonly ImmutableArray _parameterDeclaredScopes; private readonly ImmutableArray _defaultValues; private readonly SeparatedSyntaxList? _parameterSyntaxList; private readonly bool _isAsync; @@ -1393,7 +1394,7 @@ internal PlainUnboundLambdaState( ImmutableArray parameterIsDiscardOpt, ImmutableArray parameterTypesWithAnnotations, ImmutableArray parameterRefKinds, - ImmutableArray parameterDeclaredScopes, + ImmutableArray parameterDeclaredScopes, ImmutableArray defaultValues, SeparatedSyntaxList? parameterSyntaxList, bool isAsync, @@ -1486,10 +1487,10 @@ public override RefKind RefKind(int index) return _parameterRefKinds.IsDefault ? Microsoft.CodeAnalysis.RefKind.None : _parameterRefKinds[index]; } - public override DeclarationScope DeclaredScope(int index) + public override ScopedKind DeclaredScope(int index) { Debug.Assert(0 <= index && index < _parameterTypesWithAnnotations.Length); - return _parameterDeclaredScopes.IsDefault ? DeclarationScope.Unscoped : _parameterDeclaredScopes[index]; + return _parameterDeclaredScopes.IsDefault ? ScopedKind.None : _parameterDeclaredScopes[index]; } public override ParameterSyntax ParameterSyntax(int index) diff --git a/src/Compilers/CSharp/Portable/BoundTree/VariablePendingInference.cs b/src/Compilers/CSharp/Portable/BoundTree/VariablePendingInference.cs index 674495d6b5b50..d3e48fe15330b 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/VariablePendingInference.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/VariablePendingInference.cs @@ -64,7 +64,7 @@ internal BoundExpression SetInferredTypeWithAnnotations(TypeWithAnnotations type Binder.CheckRestrictedTypeInAsyncMethod(localSymbol.ContainingSymbol, type.Type, diagnosticsOpt, typeOrDesignationSyntax); - if (localSymbol.Scope == DeclarationScope.ValueScoped && !type.Type.IsErrorTypeOrRefLikeType()) + if (localSymbol.Scope == ScopedKind.ScopedValue && !type.Type.IsErrorTypeOrRefLikeType()) { diagnosticsOpt.Add(ErrorCode.ERR_ScopedRefAndRefStructOnly, (typeOrDesignationSyntax is TypeSyntax typeSyntax ? typeSyntax.SkipScoped(out _).SkipRef() : typeOrDesignationSyntax).Location); diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index e538c1ad57f46..8e171054627e2 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -7365,7 +7365,13 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Types and aliases cannot be named 'scoped'. - UnscopedRefAttribute cannot be applied to this item because it is unscoped by default. + UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. + + + UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + + + UnscopedRefAttribute cannot be applied to an interface implementation. Target runtime doesn't support ref fields. diff --git a/src/Compilers/CSharp/Portable/CodeGen/CodeGenerator.cs b/src/Compilers/CSharp/Portable/CodeGen/CodeGenerator.cs index 2fc345eb025a8..00281e39e2914 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/CodeGenerator.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/CodeGenerator.cs @@ -224,14 +224,14 @@ public void Generate( hasStackAlloc = _sawStackalloc; Debug.Assert(_asyncCatchHandlerOffset >= 0); - asyncCatchHandlerOffset = _builder.GetILOffsetFromMarker(_asyncCatchHandlerOffset); + asyncCatchHandlerOffset = _diagnostics.HasAnyErrors() ? -1 : _builder.GetILOffsetFromMarker(_asyncCatchHandlerOffset); ArrayBuilder yieldPoints = _asyncYieldPoints; ArrayBuilder resumePoints = _asyncResumePoints; Debug.Assert((yieldPoints == null) == (resumePoints == null)); - if (yieldPoints == null) + if (yieldPoints == null || _diagnostics.HasAnyErrors()) { asyncYieldPoints = ImmutableArray.Empty; asyncResumePoints = ImmutableArray.Empty; diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitAddress.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitAddress.cs index 12f37a4d90c57..fc00512327802 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitAddress.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitAddress.cs @@ -48,6 +48,10 @@ private LocalDefinition EmitAddress(BoundExpression expression, AddressKind addr EmitComplexConditionalReceiverAddress((BoundComplexConditionalReceiver)expression); break; + case BoundKind.ComplexReceiver: + EmitComplexReceiverAddress((BoundComplexReceiver)expression); + break; + case BoundKind.Parameter: return EmitParameterAddress((BoundParameter)expression, addressKind); @@ -209,7 +213,7 @@ private LocalDefinition EmitPassByCopyAddress(BoundPassByCopy passByCopyExpr, Ad /// private void EmitConditionalOperatorAddress(BoundConditionalOperator expr, AddressKind addressKind) { - Debug.Assert(expr.ConstantValue == null, "Constant value should have been emitted directly"); + Debug.Assert(expr.ConstantValueOpt == null, "Constant value should have been emitted directly"); object consequenceLabel = new object(); object doneLabel = new object(); diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitArrayInitializer.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitArrayInitializer.cs index 5cb2cc8c3b7c3..d99d9b010a19b 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitArrayInitializer.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitArrayInitializer.cs @@ -104,7 +104,7 @@ private static bool ShouldEmitInitExpression(bool includeConstants, BoundExpress return false; } - return includeConstants || init.ConstantValue == null; + return includeConstants || init.ConstantValueOpt == null; } /// @@ -214,7 +214,7 @@ private void EmitAllElementInitializersRecursive(ArrayTypeSymbol arrayType, private static ConstantValue AsConstOrDefault(BoundExpression init) { - ConstantValue initConstantValueOpt = init.ConstantValue; + ConstantValue initConstantValueOpt = init.ConstantValueOpt; if (initConstantValueOpt != null) { @@ -313,7 +313,7 @@ private void InitializerCountRecursive(ImmutableArray inits, re if (!init.IsDefaultValue()) { initCount += 1; - if (init.ConstantValue != null) + if (init.ConstantValueOpt != null) { constInits += 1; } @@ -495,19 +495,19 @@ private bool TryEmitReadonlySpanAsBlobWrapper(NamedTypeSymbol spanType, BoundExp if (start is not null) { // The start expression needs to be 0. - if (start.ConstantValue?.IsDefaultValue != true || start.ConstantValue.Discriminator != ConstantValueTypeDiscriminator.Int32) + if (start.ConstantValueOpt?.IsDefaultValue != true || start.ConstantValueOpt.Discriminator != ConstantValueTypeDiscriminator.Int32) { return false; } // The length expression needs to be an Int32, and it needs to be in the range [0, elementCount]. Debug.Assert(length is not null); - if (length.ConstantValue?.Discriminator != ConstantValueTypeDiscriminator.Int32) + if (length.ConstantValueOpt?.Discriminator != ConstantValueTypeDiscriminator.Int32) { return false; } - lengthForConstructor = length.ConstantValue.Int32Value; + lengthForConstructor = length.ConstantValueOpt.Int32Value; if (lengthForConstructor > elementCount || lengthForConstructor < 0) { @@ -727,7 +727,7 @@ private int TryGetRawDataForArrayInit(BoundArrayInitialization initializer, out } var initializers = initializer.Initializers; - if (initializers.Any(static init => init.ConstantValue == null)) + if (initializers.Any(static init => init.ConstantValueOpt == null)) { return -1; } @@ -743,7 +743,7 @@ private int TryGetRawDataForArrayInit(BoundArrayInitialization initializer, out foreach (var init in initializer.Initializers) { - init.ConstantValue.Serialize(writer); + init.ConstantValueOpt.Serialize(writer); } data = writer.ToImmutableArray(); diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitConversion.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitConversion.cs index 2430a0906b2da..96eeb2383ecab 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitConversion.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitConversion.cs @@ -199,7 +199,7 @@ private void EmitIdentityConversion(BoundConversion conversion) // doing this or marking somewhere else that this is necessary. // Don't need to do this for constants, however. - if (conversion.Operand.ConstantValue == null) + if (conversion.Operand.ConstantValueOpt == null) { EmitNumericConversion(conversion); } diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs index c5151726f5c9d..97946afe641d4 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs @@ -39,7 +39,7 @@ private void EmitExpression(BoundExpression expression, bool used) return; } - var constantValue = expression.ConstantValue; + var constantValue = expression.ConstantValueOpt; if (constantValue != null) { if (!used) @@ -316,6 +316,10 @@ private void EmitExpressionCore(BoundExpression expression, bool used) EmitComplexConditionalReceiver((BoundComplexConditionalReceiver)expression, used); break; + case BoundKind.ComplexReceiver: + EmitComplexReceiver((BoundComplexReceiver)expression, used); + break; + case BoundKind.PseudoVariable: EmitPseudoVariableValue((BoundPseudoVariable)expression, used); break; @@ -365,7 +369,11 @@ private void EmitComplexConditionalReceiver(BoundComplexConditionalReceiver expr EmitExpression(expression.ReferenceTypeReceiver, used); _builder.EmitBranch(ILOpCode.Br, doneLabel); - _builder.AdjustStack(-1); + + if (used) + { + _builder.AdjustStack(-1); + } _builder.MarkLabel(whenValueTypeLabel); EmitExpression(expression.ValueTypeReceiver, used); @@ -382,7 +390,7 @@ private void EmitLoweredConditionalAccessExpression(BoundLoweredConditionalAcces Debug.Assert(!receiverType.IsValueType || (receiverType.IsNullableType() && expression.HasValueMethodOpt != null), "conditional receiver cannot be a struct"); - var receiverConstant = receiver.ConstantValue; + var receiverConstant = receiver.ConstantValueOpt; if (receiverConstant?.IsNull == false) { // const but not null, must be a reference type @@ -408,9 +416,12 @@ private void EmitLoweredConditionalAccessExpression(BoundLoweredConditionalAcces // or if we have a ref-constrained T (to do box just once) // or if we deal with stack local (reads are destructive) // or if we have default(T) (to do box just once) - var nullCheckOnCopy = LocalRewriter.CanChangeValueBetweenReads(receiver, localsMayBeAssignedOrCaptured: false) || + var nullCheckOnCopy = (expression.ForceCopyOfNullableValueType && notConstrained && + ((TypeParameterSymbol)receiverType).EffectiveInterfacesNoUseSiteDiagnostics.IsEmpty) || // This could be a nullable value type, which must be copied in order to not mutate the original value + LocalRewriter.CanChangeValueBetweenReads(receiver, localsMayBeAssignedOrCaptured: false) || (receiverType.IsReferenceType && receiverType.TypeKind == TypeKind.TypeParameter) || - (receiver.Kind == BoundKind.Local && IsStackLocal(((BoundLocal)receiver).LocalSymbol)); + (receiver.Kind == BoundKind.Local && IsStackLocal(((BoundLocal)receiver).LocalSymbol)) || + (notConstrained && IsConditionalConstrainedCallThatMustUseTempForReferenceTypeReceiverWalker.Analyze(expression)); // ===== RECEIVER if (nullCheckOnCopy) @@ -562,6 +573,60 @@ private void EmitLoweredConditionalAccessExpression(BoundLoweredConditionalAcces } } + private sealed class IsConditionalConstrainedCallThatMustUseTempForReferenceTypeReceiverWalker : BoundTreeWalkerWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator + { + private readonly BoundLoweredConditionalAccess _conditionalAccess; + private bool? _result; + + private IsConditionalConstrainedCallThatMustUseTempForReferenceTypeReceiverWalker(BoundLoweredConditionalAccess conditionalAccess) + : base() + { + _conditionalAccess = conditionalAccess; + } + + public static bool Analyze(BoundLoweredConditionalAccess conditionalAccess) + { + var walker = new IsConditionalConstrainedCallThatMustUseTempForReferenceTypeReceiverWalker(conditionalAccess); + walker.Visit(conditionalAccess.WhenNotNull); + Debug.Assert(walker._result.HasValue); + return walker._result.GetValueOrDefault(); + } + + public override BoundNode Visit(BoundNode node) + { + if (_result.HasValue) + { + return null; + } + + return base.Visit(node); + } + + public override BoundNode VisitCall(BoundCall node) + { + if (node.ReceiverOpt is BoundConditionalReceiver { Id: var id } && id == _conditionalAccess.Id) + { + Debug.Assert(!_result.HasValue); + _result = !IsSafeToDereferenceReceiverRefAfterEvaluatingArguments(node.Arguments); + return null; + } + + return base.VisitCall(node); + } + + public override BoundNode VisitConditionalReceiver(BoundConditionalReceiver node) + { + if (node.Id == _conditionalAccess.Id) + { + Debug.Assert(!_result.HasValue); + _result = false; + return null; + } + + return base.VisitConditionalReceiver(node); + } + } + private void EmitConditionalReceiver(BoundConditionalReceiver expression, bool used) { Debug.Assert(!expression.Type.IsValueType); @@ -1400,7 +1465,7 @@ private bool CanUseCallOnRefTypeReceiver(BoundExpression receiver) Debug.Assert(receiver.Type.IsVerifierReference(), "this is not a reference"); Debug.Assert(receiver.Kind != BoundKind.BaseReference, "base should always use call"); - var constVal = receiver.ConstantValue; + var constVal = receiver.ConstantValueOpt; if (constVal != null) { // only when this is a constant Null, we need a callvirt @@ -1574,7 +1639,6 @@ private void EmitInstanceCallExpression(BoundCall call, UseKind useKind) var receiver = call.ReceiverOpt; var arguments = call.Arguments; LocalDefinition tempOpt = null; - LocalDefinition cloneTemp = null; Debug.Assert(!method.IsStatic && method.RequiresInstanceReceiver); @@ -1648,59 +1712,7 @@ private void EmitInstanceCallExpression(BoundCall call, UseKind useKind) } else { - // receiver is generic and method must come from the base or an interface or a generic constraint - // if the receiver is actually a value type it would need to be boxed. - // let .constrained sort this out. - callKind = receiverType.IsReferenceType && !IsRef(receiver) ? - CallKind.CallVirt : - CallKind.ConstrainedCallVirt; - - tempOpt = EmitReceiverRef(receiver, callKind == CallKind.ConstrainedCallVirt ? AddressKind.Constrained : AddressKind.Writeable); - - if (callKind == CallKind.ConstrainedCallVirt && tempOpt is null && !receiverType.IsValueType && - !ReceiverIsKnownToReferToTempIfReferenceType(call.ReceiverOpt) && - !IsSafeToDereferenceReceiverRefAfterEvaluatingArguments(call.Arguments)) - { - // A case where T is actually a class must be handled specially. - // Taking a reference to a class instance is fragile because the value behind the - // reference might change while arguments are evaluated. However, the call should be - // performed on the instance that is behind reference at the time we push the - // reference to the stack. So, for a class we need to emit a reference to a temporary - // location, rather than to the original location - - // Struct values are never nulls. - // We will emit a check for such case, but the check is really a JIT-time - // constant since JIT will know if T is a struct or not. - - // if ((object)default(T) == null) - // { - // temp = receiverRef - // receiverRef = ref temp - // } - - object whenNotNullLabel = null; - - if (!receiverType.IsReferenceType) - { - // if ((object)default(T) == null) - EmitDefaultValue(receiverType, true, receiver.Syntax); - EmitBox(receiverType, receiver.Syntax); - whenNotNullLabel = new object(); - _builder.EmitBranch(ILOpCode.Brtrue, whenNotNullLabel); - } - - // temp = receiverRef - // receiverRef = ref temp - EmitLoadIndirect(receiverType, receiver.Syntax); - cloneTemp = AllocateTemp(receiverType, receiver.Syntax); - _builder.EmitLocalStore(cloneTemp); - _builder.EmitLocalAddress(cloneTemp); - - if (whenNotNullLabel is not null) - { - _builder.MarkLabel(whenNotNullLabel); - } - } + tempOpt = emitGenericReceiver(call, out callKind); } // When emitting a callvirt to a virtual method we always emit the method info of the @@ -1776,7 +1788,140 @@ private void EmitInstanceCallExpression(BoundCall call, UseKind useKind) EmitCallCleanup(call.Syntax, useKind, method); FreeOptTemp(tempOpt); - FreeOptTemp(cloneTemp); + + [MethodImpl(MethodImplOptions.NoInlining)] + LocalDefinition emitGenericReceiver(BoundCall call, out CallKind callKind) + { + var receiver = call.ReceiverOpt; + var receiverType = receiver.Type; + + // receiver is generic and method must come from the base or an interface or a generic constraint + // if the receiver is actually a value type it would need to be boxed. + // let .constrained sort this out. + callKind = receiverType.IsReferenceType && !IsRef(receiver) ? + CallKind.CallVirt : + CallKind.ConstrainedCallVirt; + + LocalDefinition tempOpt = EmitReceiverRef(receiver, callKind == CallKind.ConstrainedCallVirt ? AddressKind.Constrained : AddressKind.Writeable); + + if (callKind == CallKind.ConstrainedCallVirt && tempOpt is null && !receiverType.IsValueType && + !ReceiverIsKnownToReferToTempIfReferenceType(receiver) && + !IsSafeToDereferenceReceiverRefAfterEvaluatingArguments(call.Arguments)) + { + // A case where T is actually a class must be handled specially. + // Taking a reference to a class instance is fragile because the value behind the + // reference might change while arguments are evaluated. However, the call should be + // performed on the instance that is behind reference at the time we push the + // reference to the stack. So, for a class we need to emit a reference to a temporary + // location, rather than to the original location + + // We will emit a runtime check for a class, but the check is really a JIT-time + // constant since JIT will know if T is a struct or not. + + // if (!typeof(T).IsValueType) + // { + // temp = receiverRef + // receiverRef = ref temp + // } + + object whenValueTypeLabel = null; + + if (!receiverType.IsReferenceType) + { + // if (!typeof(T).IsValueType) + whenValueTypeLabel = TryEmitIsValueTypeBranch(receiverType, receiver.Syntax); + } + + // temp = receiverRef + // receiverRef = ref temp + EmitLoadIndirect(receiverType, receiver.Syntax); + tempOpt = AllocateTemp(receiverType, receiver.Syntax); + _builder.EmitLocalStore(tempOpt); + _builder.EmitLocalAddress(tempOpt); + + if (whenValueTypeLabel is not null) + { + _builder.MarkLabel(whenValueTypeLabel); + } + } + + return tempOpt; + } + } + + private object TryEmitIsValueTypeBranch(TypeSymbol type, SyntaxNode syntax) + { + if (Binder.GetWellKnownTypeMember(_module.Compilation, WellKnownMember.System_Type__GetTypeFromHandle, _diagnostics, syntax: syntax, isOptional: false) is MethodSymbol getTypeFromHandle && + Binder.GetWellKnownTypeMember(_module.Compilation, WellKnownMember.System_Type__get_IsValueType, _diagnostics, syntax: syntax, isOptional: false) is MethodSymbol getIsValueType) + { + _builder.EmitOpCode(ILOpCode.Ldtoken); + EmitSymbolToken(type, syntax); + _builder.EmitOpCode(ILOpCode.Call, stackAdjustment: 0); // argument off, return value on + EmitSymbolToken(getTypeFromHandle, syntax, null); + _builder.EmitOpCode(ILOpCode.Call, stackAdjustment: 0); // instance off, return value on + EmitSymbolToken(getIsValueType, syntax, null); + var whenValueTypeLabel = new object(); + _builder.EmitBranch(ILOpCode.Brtrue, whenValueTypeLabel); + + return whenValueTypeLabel; + } + + return null; + } + + private void EmitComplexReceiver(BoundComplexReceiver expression, bool used) + { + Debug.Assert(!used); + Debug.Assert(!expression.Type.IsReferenceType); + Debug.Assert(!expression.Type.IsValueType); + + var receiverType = expression.Type; + + // if (!typeof(T).IsValueType) + object whenValueTypeLabel = TryEmitIsValueTypeBranch(receiverType, expression.Syntax); + + EmitExpression(expression.ReferenceTypeReceiver, used); + var doneLabel = new object(); + _builder.EmitBranch(ILOpCode.Br, doneLabel); + + if (whenValueTypeLabel is not null) + { + if (used) + { + _builder.AdjustStack(-1); + } + + _builder.MarkLabel(whenValueTypeLabel); + EmitExpression(expression.ValueTypeReceiver, used); + } + + _builder.MarkLabel(doneLabel); + } + + private void EmitComplexReceiverAddress(BoundComplexReceiver expression) + { + Debug.Assert(!expression.Type.IsReferenceType); + Debug.Assert(!expression.Type.IsValueType); + + var receiverType = expression.Type; + + // if (!typeof(T).IsValueType) + object whenValueTypeLabel = TryEmitIsValueTypeBranch(receiverType, expression.Syntax); + + var receiverTemp = EmitAddress(expression.ReferenceTypeReceiver, AddressKind.ReadOnly); + Debug.Assert(receiverTemp == null); + var doneLabel = new Object(); + _builder.EmitBranch(ILOpCode.Br, doneLabel); + + if (whenValueTypeLabel is not null) + { + _builder.AdjustStack(-1); + _builder.MarkLabel(whenValueTypeLabel); + // we will not write through this receiver, but it could be a target of mutating calls + EmitReceiverRef(expression.ValueTypeReceiver, AddressKind.Constrained); + } + + _builder.MarkLabel(doneLabel); } internal static bool IsPossibleReferenceTypeReceiverOfConstrainedCall(BoundExpression receiver) @@ -1800,7 +1945,9 @@ internal static bool ReceiverIsKnownToReferToTempIfReferenceType(BoundExpression if (receiver is BoundLocal { LocalSymbol.IsKnownToReferToTempIfReferenceType: true } or - BoundComplexConditionalReceiver) + BoundComplexConditionalReceiver or + BoundComplexReceiver or + BoundConditionalReceiver { Type: { IsReferenceType: false, IsValueType: false } }) { return true; } @@ -1817,7 +1964,7 @@ static bool isSafeToDereferenceReceiverRefAfterEvaluatingArgument(BoundExpressio var current = expression; while (true) { - if (current.ConstantValue != null) + if (current.ConstantValueOpt != null) { return true; } @@ -2300,7 +2447,7 @@ private bool TryEmitAssignmentInPlace(BoundAssignmentOperator assignmentOperator // in-place is not advantageous for reference types or constants if (!rightType.IsTypeParameter()) { - if (rightType.IsReferenceType || (right.ConstantValue != null && rightType.SpecialType != SpecialType.System_Decimal)) + if (rightType.IsReferenceType || (right.ConstantValueOpt != null && rightType.SpecialType != SpecialType.System_Decimal)) { return false; } @@ -3361,7 +3508,7 @@ private void EmitFieldInfoExpression(BoundFieldInfo node) /// private void EmitConditionalOperator(BoundConditionalOperator expr, bool used) { - Debug.Assert(expr.ConstantValue == null, "Constant value should have been emitted directly"); + Debug.Assert(expr.ConstantValueOpt == null, "Constant value should have been emitted directly"); object consequenceLabel = new object(); object doneLabel = new object(); diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitOperators.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitOperators.cs index 09765130dbe52..f9f22aa26413d 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitOperators.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitOperators.cs @@ -91,7 +91,7 @@ private void EmitBinaryOperator(BoundBinaryOperator expression) { BoundExpression child = expression.Left; - if (child.Kind != BoundKind.BinaryOperator || child.ConstantValue != null) + if (child.Kind != BoundKind.BinaryOperator || child.ConstantValueOpt != null) { EmitBinaryOperatorSimple(expression); return; @@ -115,7 +115,7 @@ private void EmitBinaryOperator(BoundBinaryOperator expression) stack.Push(binary); child = binary.Left; - if (child.Kind != BoundKind.BinaryOperator || child.ConstantValue != null) + if (child.Kind != BoundKind.BinaryOperator || child.ConstantValueOpt != null) { break; } @@ -357,12 +357,12 @@ private void EmitBinaryCondOperator(BoundBinaryOperator binOp, bool sense) case BinaryOperatorKind.Equal: - var constant = binOp.Left.ConstantValue; + var constant = binOp.Left.ConstantValueOpt; var comparand = binOp.Right; if (constant == null) { - constant = comparand.ConstantValue; + constant = comparand.ConstantValueOpt; comparand = binOp.Left; } @@ -481,7 +481,7 @@ private void EmitCondExpr(BoundExpression condition, bool sense) Debug.Assert(condition.Type.SpecialType == SpecialType.System_Boolean); - var constantValue = condition.ConstantValue; + var constantValue = condition.ConstantValueOpt; if (constantValue != null) { Debug.Assert(constantValue.Discriminator == ConstantValueTypeDiscriminator.Boolean); diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitStackAllocInitializer.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitStackAllocInitializer.cs index 70a086c49e21a..8c3e24f521911 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitStackAllocInitializer.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitStackAllocInitializer.cs @@ -47,7 +47,7 @@ private void EmitStackAllocInitializers(TypeSymbol type, BoundArrayInitializatio EmitElementStackAllocInitializers(elementType, initExprs, includeConstants: false); } } - else if (elementType.SpecialType.SizeInBytes() == 1) + else if (elementType.EnumUnderlyingTypeOrSelf().SpecialType.SizeInBytes() == 1) { // Initialize the stackalloc by copying the data from a metadata blob var field = _builder.module.GetFieldForData(data, alignment: 1, inits.Syntax, _diagnostics.DiagnosticBag); @@ -76,9 +76,7 @@ private ArrayInitializerStyle ShouldEmitBlockInitializerForStackAlloc(TypeSymbol return ArrayInitializerStyle.Element; } - elementType = elementType.EnumUnderlyingTypeOrSelf(); - - if (elementType.SpecialType.IsBlittable()) + if (elementType.EnumUnderlyingTypeOrSelf().SpecialType.IsBlittable()) { int initCount = 0; int constCount = 0; @@ -115,7 +113,7 @@ private void StackAllocInitializerCount(ImmutableArray inits, r Debug.Assert(!(init is BoundArrayInitialization), "Nested initializers are not allowed for stackalloc"); initCount += 1; - if (init.ConstantValue != null) + if (init.ConstantValueOpt != null) { constInits += 1; } @@ -125,10 +123,10 @@ private void StackAllocInitializerCount(ImmutableArray inits, r private void EmitElementStackAllocInitializers(TypeSymbol elementType, ImmutableArray inits, bool includeConstants) { int index = 0; - int elementTypeSizeInBytes = elementType.SpecialType.SizeInBytes(); + int elementTypeSizeInBytes = elementType.EnumUnderlyingTypeOrSelf().SpecialType.SizeInBytes(); foreach (BoundExpression init in inits) { - if (includeConstants || init.ConstantValue == null) + if (includeConstants || init.ConstantValueOpt == null) { _builder.EmitOpCode(ILOpCode.Dup); EmitPointerElementAccess(init, elementType, elementTypeSizeInBytes, index); diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitStatement.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitStatement.cs index 85ce3324f8dcc..54276a46f7ced 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitStatement.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitStatement.cs @@ -232,7 +232,7 @@ private static BoundExpression TryReduce(BoundBinaryOperator condition, ref bool opKind == BinaryOperatorKind.NotEqual); BoundExpression nonConstOp; - BoundExpression constOp = (condition.Left.ConstantValue != null) ? condition.Left : null; + BoundExpression constOp = (condition.Left.ConstantValueOpt != null) ? condition.Left : null; if (constOp != null) { @@ -240,7 +240,7 @@ private static BoundExpression TryReduce(BoundBinaryOperator condition, ref bool } else { - constOp = (condition.Right.ConstantValue != null) ? condition.Right : null; + constOp = (condition.Right.ConstantValueOpt != null) ? condition.Right : null; if (constOp == null) { return null; @@ -255,7 +255,7 @@ private static BoundExpression TryReduce(BoundBinaryOperator condition, ref bool } bool isBool = nonConstType.PrimitiveTypeCode == Microsoft.Cci.PrimitiveTypeCode.Boolean; - bool isZero = constOp.ConstantValue.IsDefaultValue; + bool isZero = constOp.ConstantValueOpt.IsDefaultValue; // bool is special, only it can be compared to true and false... if (!isBool && !isZero) @@ -395,9 +395,9 @@ private void EmitCondBranchCore(BoundExpression condition, ref object dest, bool ILOpCode ilcode; - if (condition.ConstantValue != null) + if (condition.ConstantValueOpt != null) { - bool taken = condition.ConstantValue.IsDefaultValue != sense; + bool taken = condition.ConstantValueOpt.IsDefaultValue != sense; if (taken) { @@ -1126,7 +1126,7 @@ private void EmitSwitchHeader( KeyValuePair[] switchCaseLabels, LabelSymbol fallThroughLabel) { - Debug.Assert(expression.ConstantValue == null); + Debug.Assert(expression.ConstantValueOpt == null); Debug.Assert((object)expression.Type != null && (expression.Type.IsValidV6SwitchGoverningType() || expression.Type.IsSpanOrReadOnlySpanChar())); Debug.Assert(switchCaseLabels.Length > 0); diff --git a/src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs b/src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs index f310e54dd8226..a95eece06d718 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs @@ -9,6 +9,7 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Linq; +using System.Runtime.CompilerServices; using System.Text; using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.CSharp.Symbols; @@ -465,7 +466,7 @@ private BoundExpression VisitExpressionCore(BoundExpression node, ExprContext co _context = context; // Do not recurse into constant expressions. Their children do not push any values. - var result = node.ConstantValue == null ? + var result = node.ConstantValueOpt == null ? node = (BoundExpression)base.Visit(node) : node; @@ -1247,7 +1248,7 @@ public override BoundNode VisitObjectCreationExpression(BoundObjectCreationExpre Debug.Assert(node.InitializerExpressionOpt == null); return node.Update(constructor, rewrittenArguments, node.ArgumentNamesOpt, node.ArgumentRefKindsOpt, - node.Expanded, node.ArgsToParamsOpt, node.DefaultArguments, node.ConstantValue, initializerExpressionOpt: null, node.Type); + node.Expanded, node.ArgsToParamsOpt, node.DefaultArguments, node.ConstantValueOpt, initializerExpressionOpt: null, node.Type); } public override BoundNode VisitArrayAccess(BoundArrayAccess node) @@ -1401,7 +1402,7 @@ public override BoundNode VisitBinaryOperator(BoundBinaryOperator node) { BoundExpression child = node.Left; - if (child.Kind != BoundKind.BinaryOperator || child.ConstantValue != null) + if (child.Kind != BoundKind.BinaryOperator || child.ConstantValueOpt != null) { return VisitBinaryOperatorSimple(node); } @@ -1417,7 +1418,7 @@ public override BoundNode VisitBinaryOperator(BoundBinaryOperator node) stack.Push(binary); child = binary.Left; - if (child.Kind != BoundKind.BinaryOperator || child.ConstantValue != null) + if (child.Kind != BoundKind.BinaryOperator || child.ConstantValueOpt != null) { break; } @@ -1451,7 +1452,7 @@ public override BoundNode VisitBinaryOperator(BoundBinaryOperator node) } var type = this.VisitType(binary.Type); - left = binary.Update(binary.OperatorKind, binary.ConstantValue, binary.Method, binary.ConstrainedToType, binary.ResultKind, left, right, type); + left = binary.Update(binary.OperatorKind, binary.ConstantValueOpt, binary.Method, binary.ConstrainedToType, binary.ResultKind, left, right, type); if (stack.Count == 0) { @@ -1485,7 +1486,7 @@ private BoundNode VisitBinaryOperatorSimple(BoundBinaryOperator node) EnsureStackState(cookie); // implicit label here - return node.Update(node.OperatorKind, node.ConstantValue, node.Method, node.ConstrainedToType, node.ResultKind, left, right, node.Type); + return node.Update(node.OperatorKind, node.ConstantValueOpt, node.Method, node.ConstrainedToType, node.ResultKind, left, right, node.Type); } return base.VisitBinaryOperator(node); @@ -1537,7 +1538,7 @@ public override BoundNode VisitLoweredConditionalAccess(BoundLoweredConditionalA _counter += 1; } - return node.Update(receiver, node.HasValueMethodOpt, whenNotNull, whenNull, node.Id, node.Type); + return node.Update(receiver, node.HasValueMethodOpt, whenNotNull, whenNull, node.Id, node.ForceCopyOfNullableValueType, node.Type); } public override BoundNode VisitComplexConditionalReceiver(BoundComplexConditionalReceiver node) @@ -1563,6 +1564,43 @@ public override BoundNode VisitComplexConditionalReceiver(BoundComplexConditiona return node.Update(valueTypeReceiver, referenceTypeReceiver, node.Type); } + public override BoundNode VisitComplexReceiver(BoundComplexReceiver node) + { + EnsureOnlyEvalStack(); + + var origStack = StackDepth(); + + PushEvalStack(null, ExprContext.None); + + var cookie = GetStackStateCookie(); // implicit goto here + + SetStackDepth(origStack); // consequence is evaluated with original stack + + var valueTypeReceiver = (BoundExpression)this.Visit(node.ValueTypeReceiver); + + EnsureStackState(cookie); // implicit label here + + SetStackDepth(origStack); // alternative is evaluated with original stack + + var unwrappedSequence = node.ReferenceTypeReceiver; + + while (unwrappedSequence is BoundSequence sequence) + { + unwrappedSequence = sequence.Value; + } + + if (unwrappedSequence is BoundLocal { LocalSymbol: { } localSymbol }) + { + ShouldNotSchedule(localSymbol); + } + + var referenceTypeReceiver = (BoundExpression)this.Visit(node.ReferenceTypeReceiver); + + EnsureStackState(cookie); // implicit label here + + return node.Update(valueTypeReceiver, referenceTypeReceiver, node.Type); + } + public override BoundNode VisitUnaryOperator(BoundUnaryOperator node) { // checked(-x) is emitted as "0 - x" @@ -1964,7 +2002,7 @@ public override BoundNode Visit(BoundNode node) // so we will not go into constant nodes. // CodeGen will not do that either. var asExpression = node as BoundExpression; - if (asExpression != null && asExpression.ConstantValue != null) + if (asExpression != null && asExpression.ConstantValueOpt != null) { result = node; } @@ -1982,7 +2020,7 @@ public override BoundNode VisitBinaryOperator(BoundBinaryOperator node) { BoundExpression child = node.Left; - if (child.Kind != BoundKind.BinaryOperator || child.ConstantValue != null) + if (child.Kind != BoundKind.BinaryOperator || child.ConstantValueOpt != null) { return base.VisitBinaryOperator(node); } @@ -1998,7 +2036,7 @@ public override BoundNode VisitBinaryOperator(BoundBinaryOperator node) stack.Push(binary); child = binary.Left; - if (child.Kind != BoundKind.BinaryOperator || child.ConstantValue != null) + if (child.Kind != BoundKind.BinaryOperator || child.ConstantValueOpt != null) { break; } @@ -2013,7 +2051,7 @@ public override BoundNode VisitBinaryOperator(BoundBinaryOperator node) binary = stack.Pop(); var right = (BoundExpression)this.Visit(binary.Right); var type = this.VisitType(binary.Type); - left = binary.Update(binary.OperatorKind, binary.ConstantValue, binary.Method, binary.ConstrainedToType, binary.ResultKind, left, right, type); + left = binary.Update(binary.OperatorKind, binary.ConstantValueOpt, binary.Method, binary.ConstrainedToType, binary.ResultKind, left, right, type); if (stack.Count == 0) { @@ -2214,7 +2252,14 @@ internal override SyntaxNode ScopeDesignatorOpt get { return null; } } - internal override LocalSymbol WithSynthesizedLocalKindAndSyntax(SynthesizedLocalKind kind, SyntaxNode syntax) + internal override LocalSymbol WithSynthesizedLocalKindAndSyntax( + SynthesizedLocalKind kind, SyntaxNode syntax +#if DEBUG + , + [CallerLineNumber] int createdAtLineNumber = 0, + [CallerFilePath] string createdAtFilePath = null +#endif + ) { throw new NotImplementedException(); } @@ -2279,18 +2324,6 @@ public override RefKind RefKind get { return RefKind.None; } } - /// - /// Compiler should always be synthesizing locals with correct escape semantics. - /// Checking escape scopes is not valid here. - /// - internal override uint ValEscapeScope => throw ExceptionUtilities.Unreachable(); - - /// - /// Compiler should always be synthesizing locals with correct escape semantics. - /// Checking escape scopes is not valid here. - /// - internal override uint RefEscapeScope => throw ExceptionUtilities.Unreachable(); - - internal override DeclarationScope Scope => DeclarationScope.Unscoped; + internal override ScopedKind Scope => ScopedKind.None; } } diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs index 7bb9dbd39ac54..47b7daf1124c7 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs @@ -3897,7 +3897,7 @@ protected override INamedTypeSymbol CommonCreateAnonymousTypeSymbol( var name = memberNames[i]; var location = memberLocations.IsDefault ? Location.None : memberLocations[i]; var nullableAnnotation = memberNullableAnnotations.IsDefault ? NullableAnnotation.Oblivious : memberNullableAnnotations[i].ToInternalAnnotation(); - fields.Add(new AnonymousTypeField(name, location, TypeWithAnnotations.Create(type, nullableAnnotation), RefKind.None, DeclarationScope.Unscoped)); + fields.Add(new AnonymousTypeField(name, location, TypeWithAnnotations.Create(type, nullableAnnotation), RefKind.None, ScopedKind.None)); } var descriptor = new AnonymousTypeDescriptor(fields.ToImmutableAndFree(), Location.None); diff --git a/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs index e46330abd63ad..78223dd375776 100644 --- a/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs @@ -1251,7 +1251,7 @@ internal override Optional GetConstantValueWorker(CSharpSyntaxNode node, if (boundExpr == null) return default(Optional); - ConstantValue constantValue = boundExpr.ConstantValue; + ConstantValue constantValue = boundExpr.ConstantValueOpt; return constantValue == null || constantValue.IsBad ? default(Optional) : new Optional(constantValue.Value); diff --git a/src/Compilers/CSharp/Portable/Compiler/AnonymousTypeMethodBodySynthesizer.cs b/src/Compilers/CSharp/Portable/Compiler/AnonymousTypeMethodBodySynthesizer.cs index 50aa81750ce4f..2bd596d09051b 100644 --- a/src/Compilers/CSharp/Portable/Compiler/AnonymousTypeMethodBodySynthesizer.cs +++ b/src/Compilers/CSharp/Portable/Compiler/AnonymousTypeMethodBodySynthesizer.cs @@ -268,6 +268,7 @@ internal override void GenerateMethodBody(TypeCompilationState compilationState, type: property.BackingField.Type), manager.System_Object__ToString), null, id: i, + forceCopyOfNullableValueType: true, type: manager.System_String), Conversion.ImplicitReference); } diff --git a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs index 7ed98d6a3cd28..63feff68ea197 100644 --- a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs +++ b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs @@ -1044,6 +1044,8 @@ private void CompileMethod( { analyzedInitializers = InitializerRewriter.RewriteConstructor(processedInitializers.BoundInitializers, methodSymbol); processedInitializers.HasErrors = processedInitializers.HasErrors || analyzedInitializers.HasAnyErrors; + + RefSafetyAnalysis.Analyze(_compilation, methodSymbol, processedInitializers.BoundInitializers, diagsForCurrentMethod); } body = BindMethodBody( @@ -1089,7 +1091,7 @@ private void CompileMethod( { insertAt = 1; } - body = body.Update(body.Locals, body.LocalFunctions, body.Statements.Insert(insertAt, analyzedInitializers)); + body = body.Update(body.Locals, body.LocalFunctions, body.HasUnsafeModifier, body.Statements.Insert(insertAt, analyzedInitializers)); includeNonEmptyInitializersInBody = false; analyzedInitializers = null; } @@ -1865,12 +1867,15 @@ syntaxNode is ConstructorDeclarationSyntax constructorSyntax && finalNullableState: out _); } } + forSemanticModel = new MethodBodySemanticModel.InitialState(syntaxNode, methodBodyForSemanticModel, bodyBinder, snapshotManager, remappedSymbols); #if DEBUG Debug.Assert(IsEmptyRewritePossible(methodBody)); #endif + RefSafetyAnalysis.Analyze(compilation, method, methodBody, diagnostics); + switch (methodBody.Kind) { case BoundKind.ConstructorMethodBody: diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs b/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs index 8fbf8d944bf82..d01d1279c7a7a 100644 --- a/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs +++ b/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs @@ -1711,10 +1711,10 @@ internal virtual SynthesizedAttributeData SynthesizeNativeIntegerAttribute(WellK return Compilation.TrySynthesizeAttribute(member, arguments, isOptionalUse: true); } - internal SynthesizedAttributeData SynthesizeScopedRefAttribute(ParameterSymbol symbol, DeclarationScope scope) + internal SynthesizedAttributeData SynthesizeScopedRefAttribute(ParameterSymbol symbol, ScopedKind scope) { - Debug.Assert(scope != DeclarationScope.Unscoped); - Debug.Assert(!ParameterHelpers.IsRefScopedByDefault(symbol) || scope == DeclarationScope.ValueScoped); + Debug.Assert(scope != ScopedKind.None); + Debug.Assert(!ParameterHelpers.IsRefScopedByDefault(symbol) || scope == ScopedKind.ScopedValue); Debug.Assert(!symbol.IsThis); if ((object)Compilation.SourceModule != symbol.ContainingModule) diff --git a/src/Compilers/CSharp/Portable/Errors/CSDiagnosticInfo.cs b/src/Compilers/CSharp/Portable/Errors/CSDiagnosticInfo.cs index c862d44680af6..75d9625ecc940 100644 --- a/src/Compilers/CSharp/Portable/Errors/CSDiagnosticInfo.cs +++ b/src/Compilers/CSharp/Portable/Errors/CSDiagnosticInfo.cs @@ -42,6 +42,16 @@ internal CSDiagnosticInfo(ErrorCode code, object[] args, ImmutableArray _additionalLocations = additionalLocations.IsDefaultOrEmpty ? SpecializedCollections.EmptyReadOnlyList() : additionalLocations; } + private CSDiagnosticInfo(CSDiagnosticInfo original, DiagnosticSeverity severity) : base(original, severity) + { + _additionalLocations = original._additionalLocations; + } + + internal override DiagnosticInfo GetInstanceWithSeverity(DiagnosticSeverity severity) + { + return new CSDiagnosticInfo(this, severity); + } + public override IReadOnlyList AdditionalLocations => _additionalLocations; internal new ErrorCode Code => (ErrorCode)base.Code; diff --git a/src/Compilers/CSharp/Portable/Errors/DiagnosticInfoWithSymbols.cs b/src/Compilers/CSharp/Portable/Errors/DiagnosticInfoWithSymbols.cs index f33414b224345..8558918eccc1b 100644 --- a/src/Compilers/CSharp/Portable/Errors/DiagnosticInfoWithSymbols.cs +++ b/src/Compilers/CSharp/Portable/Errors/DiagnosticInfoWithSymbols.cs @@ -24,5 +24,15 @@ internal DiagnosticInfoWithSymbols(bool isWarningAsError, ErrorCode errorCode, o { this.Symbols = symbols; } + + protected DiagnosticInfoWithSymbols(DiagnosticInfoWithSymbols original, DiagnosticSeverity severity) : base(original, severity) + { + this.Symbols = original.Symbols; + } + + internal override DiagnosticInfo GetInstanceWithSeverity(DiagnosticSeverity severity) + { + return new DiagnosticInfoWithSymbols(this, severity); + } } } diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index 4e8baf89621d0..f3c4710a0985d 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -2154,9 +2154,12 @@ internal enum ErrorCode #endregion #region diagnostics introduced for C# 12.0 + ERR_ImplicitlyTypedDefaultParameter = 9098, WRN_OptionalParamValueMismatch = 9099, WRN_ParamsArrayInLambdaOnly = 9100, + ERR_UnscopedRefAttributeUnsupportedMemberTarget = 9101, + ERR_UnscopedRefAttributeInterfaceImplementation = 9102, ERR_InvalidPrimaryConstructorParameterReference = 9500, // PROTOTYPE(PrimaryConstructors): pack numbers ERR_AmbiguousPrimaryConstructorParameterAsColorColorReceiver = 9501, diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs index f57815ae64426..1a02232dc036c 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs @@ -2273,6 +2273,8 @@ internal static bool IsBuildOnlyDiagnostic(ErrorCode code) case ErrorCode.WRN_RefAssignValEscapeWider: case ErrorCode.WRN_OptionalParamValueMismatch: case ErrorCode.WRN_ParamsArrayInLambdaOnly: + case ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget: + case ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation: case ErrorCode.ERR_InvalidPrimaryConstructorParameterReference: case ErrorCode.ERR_AmbiguousPrimaryConstructorParameterAsColorColorReceiver: return false; @@ -2314,6 +2316,7 @@ internal static bool PreventsSuccessfulDelegateConversion(ErrorCode code) case ErrorCode.ERR_QueryRangeVariableSameAsTypeParam: case ErrorCode.ERR_DeprecatedCollectionInitAddStr: case ErrorCode.ERR_DeprecatedSymbolStr: + case ErrorCode.ERR_MissingPredefinedMember: return false; default: return true; diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs index 386369aad4c5e..24d2f1e42ccd0 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs @@ -667,17 +667,17 @@ protected virtual void VisitStatement(BoundStatement statement) protected static bool IsConstantTrue(BoundExpression node) { - return node.ConstantValue == ConstantValue.True; + return node.ConstantValueOpt == ConstantValue.True; } protected static bool IsConstantFalse(BoundExpression node) { - return node.ConstantValue == ConstantValue.False; + return node.ConstantValueOpt == ConstantValue.False; } protected static bool IsConstantNull(BoundExpression node) { - return node.ConstantValue == ConstantValue.Null; + return node.ConstantValueOpt == ConstantValue.Null; } /// @@ -1567,7 +1567,7 @@ public override BoundNode VisitUtf8String(BoundUtf8String node) protected void SplitIfBooleanConstant(BoundExpression node) { - if (node.ConstantValue is { IsBoolean: true, BooleanValue: bool booleanValue }) + if (node.ConstantValueOpt is { IsBoolean: true, BooleanValue: bool booleanValue }) { var unreachable = UnreachableState(); Split(); @@ -2380,7 +2380,7 @@ protected virtual void VisitBinaryOperatorChildren(ArrayBuilder.Empty, builder.ToImmutableAndFree()); + return body.Update(body.Locals, ImmutableArray.Empty, body.HasUnsafeModifier, builder.ToImmutableAndFree()); } else { @@ -178,7 +181,7 @@ internal static BoundBlock AppendImplicitReturn(BoundBlock body, MethodSymbol me ? (BoundStatement)BoundYieldBreakStatement.Synthesized(syntax) : BoundReturnStatement.Synthesized(syntax, RefKind.None, null); - return body.Update(body.Locals, body.LocalFunctions, body.Statements.Add(ret)); + return body.Update(body.Locals, body.LocalFunctions, body.HasUnsafeModifier, body.Statements.Add(ret)); } private static bool Analyze( diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.DebugVerifier.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.DebugVerifier.cs index 6c6c6bcd7e3d7..402465a057c26 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.DebugVerifier.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.DebugVerifier.cs @@ -244,7 +244,7 @@ private void VisitBinaryOperatorChildren(BoundBinaryOperatorBase node) // If the constant value of a when clause is true, it can be skipped by the dag // generator as an optimization. In that case, it's a value type and will be set // as not nullable in the output. - if (node.WhenClause?.ConstantValue != ConstantValue.True) + if (node.WhenClause?.ConstantValueOpt != ConstantValue.True) { this.Visit(node.WhenClause); } diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.PlaceholderLocal.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.PlaceholderLocal.cs index 262c1713b142b..75b434c276c6f 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.PlaceholderLocal.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.PlaceholderLocal.cs @@ -6,6 +6,7 @@ using System.Collections.Immutable; using System.Diagnostics; +using System.Runtime.CompilerServices; using Microsoft.CodeAnalysis.CSharp.Symbols; using Roslyn.Utilities; @@ -60,10 +61,15 @@ public override bool Equals(Symbol obj, TypeCompareKind compareKind) internal override ConstantValue GetConstantValue(SyntaxNode node, LocalSymbol inProgress, BindingDiagnosticBag diagnostics = null) => null; internal override ImmutableBindingDiagnostic GetConstantValueDiagnostics(BoundExpression boundInitValue) => ImmutableBindingDiagnostic.Empty; internal override SyntaxNode GetDeclaratorSyntax() => throw ExceptionUtilities.Unreachable(); - internal override LocalSymbol WithSynthesizedLocalKindAndSyntax(SynthesizedLocalKind kind, SyntaxNode syntax) => throw ExceptionUtilities.Unreachable(); - internal override uint ValEscapeScope => throw ExceptionUtilities.Unreachable(); - internal override uint RefEscapeScope => throw ExceptionUtilities.Unreachable(); - internal override DeclarationScope Scope => DeclarationScope.Unscoped; + internal override LocalSymbol WithSynthesizedLocalKindAndSyntax( + SynthesizedLocalKind kind, SyntaxNode syntax +#if DEBUG + , + [CallerLineNumber] int createdAtLineNumber = 0, + [CallerFilePath] string createdAtFilePath = null +#endif + ) => throw ExceptionUtilities.Unreachable(); + internal override ScopedKind Scope => ScopedKind.None; } } } diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs index 55aab550ecf30..dbbd1bd54d516 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs @@ -60,6 +60,7 @@ internal sealed class VariableState internal VariableState(VariablesSnapshot variables, LocalStateSnapshot variableNullableStates) { + Debug.Assert(variables.Id == variableNullableStates.Id); Variables = variables; VariableNullableStates = variableNullableStates; } @@ -743,7 +744,7 @@ void checkMemberStateOnConstructorExit(MethodSymbol constructor, Symbol member, return; } - var memberState = state[slot]; + var memberState = GetState(ref state, slot); var badState = symbolType.Type.IsPossiblyNullableReferenceTypeTypeParameter() && (annotations & FlowAnalysisAnnotations.NotNull) == 0 ? NullableFlowState.MaybeDefault : NullableFlowState.MaybeNull; @@ -770,7 +771,7 @@ void enforceMemberNotNullWhenForPendingReturn(PendingBranch pendingReturn, Bound { if (pendingReturn.IsConditionalState) { - if (returnStatement.ExpressionOpt is { ConstantValue: { IsBoolean: true, BooleanValue: bool value } }) + if (returnStatement.ExpressionOpt is { ConstantValueOpt: { IsBoolean: true, BooleanValue: bool value } }) { enforceMemberNotNullWhen(returnStatement.Syntax, sense: value, pendingReturn.State); return; @@ -794,7 +795,7 @@ void enforceMemberNotNullWhenForPendingReturn(PendingBranch pendingReturn, Bound } } } - else if (returnStatement.ExpressionOpt is { ConstantValue: { IsBoolean: true, BooleanValue: bool value } }) + else if (returnStatement.ExpressionOpt is { ConstantValueOpt: { IsBoolean: true, BooleanValue: bool value } }) { enforceMemberNotNullWhen(returnStatement.Syntax, sense: value, pendingReturn.State); } @@ -845,7 +846,7 @@ bool memberHasBadState(Symbol member, LocalState state) if (getSlotForFieldOrPropertyOrEvent(member) is int memberSlot && memberSlot > 0) { - var parameterState = state[memberSlot]; + var parameterState = GetState(ref state, memberSlot); return !parameterState.IsNotNull(); } else @@ -905,7 +906,7 @@ void makeNotNullMembersMaybeNull() var type = memberToInitialize.GetTypeOrReturnType(); if (!type.NullableAnnotation.IsOblivious()) { - this.State[memberSlot] = type.Type.IsPossiblyNullableReferenceTypeTypeParameter() ? NullableFlowState.MaybeDefault : NullableFlowState.MaybeNull; + SetState(ref this.State, memberSlot, type.Type.IsPossiblyNullableReferenceTypeTypeParameter() ? NullableFlowState.MaybeDefault : NullableFlowState.MaybeNull); } } } @@ -1059,7 +1060,7 @@ void makeMemberMaybeNull(MethodSymbol method, string memberName) if (getSlotForFieldOrPropertyOrEvent(member) is int memberSlot && memberSlot > 0) { - this.State[memberSlot] = NullableFlowState.MaybeNull; + SetState(ref this.State, memberSlot, NullableFlowState.MaybeNull); } } } @@ -1109,7 +1110,7 @@ private void EnforceNotNullWhenForPendingReturn(PendingBranch pendingReturn, Bou { if (pendingReturn.IsConditionalState) { - if (returnStatement.ExpressionOpt is { ConstantValue: { IsBoolean: true, BooleanValue: bool value } }) + if (returnStatement.ExpressionOpt is { ConstantValueOpt: { IsBoolean: true, BooleanValue: bool value } }) { EnforceParameterNotNullWhenOnExit(returnStatement.Syntax, parameters, sense: value, stateWhen: pendingReturn.State); return; @@ -1123,14 +1124,14 @@ private void EnforceNotNullWhenForPendingReturn(PendingBranch pendingReturn, Bou foreach (var parameter in parameters) { // For non-constant values, only complain if we were able to analyze a difference for this parameter between two branches - if (GetOrCreateSlot(parameter) is > 0 and var slot && pendingReturn.StateWhenTrue[slot] != pendingReturn.StateWhenFalse[slot]) + if (GetOrCreateSlot(parameter) is > 0 and var slot && GetState(ref pendingReturn.StateWhenTrue, slot) != GetState(ref pendingReturn.StateWhenFalse, slot)) { ReportParameterIfBadConditionalState(returnStatement.Syntax, parameter, sense: true, stateWhen: pendingReturn.StateWhenTrue); ReportParameterIfBadConditionalState(returnStatement.Syntax, parameter, sense: false, stateWhen: pendingReturn.StateWhenFalse); } } } - else if (returnStatement.ExpressionOpt is { ConstantValue: { IsBoolean: true, BooleanValue: bool value } }) + else if (returnStatement.ExpressionOpt is { ConstantValueOpt: { IsBoolean: true, BooleanValue: bool value } }) { // example: return (bool)true; EnforceParameterNotNullWhenOnExit(returnStatement.Syntax, parameters, sense: value, stateWhen: pendingReturn.State); @@ -1156,7 +1157,7 @@ private void EnforceParameterNotNullOnExit(SyntaxNode? syntaxOpt, LocalState sta var annotations = parameter.FlowAnalysisAnnotations; var hasNotNull = (annotations & FlowAnalysisAnnotations.NotNull) == FlowAnalysisAnnotations.NotNull; - var parameterState = state[slot]; + var parameterState = GetState(ref state, slot); if (hasNotNull && parameterState.MayBeNull()) { Location location; @@ -1212,7 +1213,7 @@ bool parameterHasBadConditionalState(ParameterSymbol parameter, bool sense, Loca var slot = GetOrCreateSlot(parameter); if (slot > 0) { - var parameterState = stateWhen[slot]; + var parameterState = GetState(ref stateWhen, slot); // On a parameter marked with MaybeNullWhen, we would have not reported an assignment warning. // We should only check if an assignment warning would have been warranted ignoring the MaybeNullWhen. @@ -1250,7 +1251,7 @@ private void EnforceNotNullIfNotNull(SyntaxNode? syntaxOpt, LocalState state, Im { if (inputParamNames.Contains(inputParam.Name) && GetOrCreateSlot(inputParam) is > 0 and int inputSlot - && state[inputSlot].IsNotNull()) + && GetState(ref state, inputSlot).IsNotNull()) { var location = syntaxOpt?.GetLocation() ?? methodMainNode.Syntax.GetLastToken().GetLocation(); if (outputParam is object) @@ -1729,6 +1730,12 @@ private static void Analyze( var previousSlot = snapshotBuilderOpt?.EnterNewWalker(symbol!) ?? -1; try { +#if DEBUG + if (initialState.HasValue) + { + Debug.Assert(walker._variables.Id == initialState.Value.Id); + } +#endif bool badRegion = false; ImmutableArray returns = walker.Analyze(ref badRegion, initialState); diagnostics?.AddRange(walker.Diagnostics); @@ -1809,6 +1816,29 @@ private void SetUpdatedSymbol(BoundNode node, Symbol originalSymbol, Symbol upda } } + private NullableFlowState GetState(ref LocalState state, int slot) + { + if (!state.Reachable) + return NullableFlowState.NotNull; + + NormalizeIfNeeded(ref state, slot, useNotNullsAsDefault: false); + return state[slot]; + } + + private void SetState(ref LocalState state, int slot, NullableFlowState value, bool useNotNullsAsDefault = false) + { + if (!state.Reachable) + return; + + NormalizeIfNeeded(ref state, slot, useNotNullsAsDefault); + state[slot] = value; + } + + private void NormalizeIfNeeded(ref LocalState state, int slot, bool useNotNullsAsDefault) + { + state.NormalizeIfNeeded(slot, this, _variables, useNotNullsAsDefault); + } + protected override void Normalize(ref LocalState state) { if (!state.Reachable) @@ -2202,7 +2232,7 @@ private void ReportNullableAssignmentIfNecessary( return; } - if (value.ConstantValue?.IsNull == true && !useLegacyWarnings) + if (value.ConstantValueOpt?.IsNull == true && !useLegacyWarnings) { // Report warning converting null literal to non-nullable reference type. // target (e.g.: `object F() => null;` or calling `void F(object y)` with `F(null)`). @@ -2416,8 +2446,6 @@ private void TrackNullableStateForAssignment( return; } - if (!this.State.HasValue(targetSlot)) Normalize(ref this.State); - var newState = valueType.State; SetStateAndTrackForFinally(ref this.State, targetSlot, newState); InheritDefaultState(targetType.Type, targetSlot); @@ -2528,8 +2556,8 @@ private void InheritNullableStateOfMember(int targetContainerSlot, int valueCont { return; } - value = this.State.HasValue(valueMemberSlot) ? - this.State[valueMemberSlot] : + value = valueMemberSlot > 0 ? + GetState(ref this.State, valueMemberSlot) : NullableFlowState.NotNull; } @@ -2568,13 +2596,14 @@ private TypeSymbol NominalSlotType(int slot) /// private void SetStateAndTrackForFinally(ref LocalState state, int slot, NullableFlowState newState) { - state[slot] = newState; + Debug.Assert(slot > 0); + SetState(ref state, slot, newState); if (newState != NullableFlowState.NotNull && NonMonotonicState.HasValue) { var tryState = NonMonotonicState.Value; if (tryState.HasVariable(slot)) { - tryState[slot] = newState.Join(tryState[slot]); + SetState(ref tryState, slot, newState.Join(GetState(ref tryState, slot)), useNotNullsAsDefault: true); NonMonotonicState = tryState; } } @@ -2637,7 +2666,7 @@ protected override LocalState UnreachableState() protected override LocalState ReachableBottomState() { // Create a reachable state in which all variables are known to be non-null. - return LocalState.ReachableState(_variables); + return LocalState.ReachableStateWithNotNulls(_variables); } private void EnterParameters() @@ -2697,7 +2726,7 @@ private void EnterParameter(ParameterSymbol parameter, TypeWithAnnotations param if (slot > 0) { var state = GetParameterState(parameterType, parameter.FlowAnalysisAnnotations).State; - this.State[slot] = state; + SetState(ref this.State, slot, state); if (EmptyStructTypeCache.IsTrackableStructType(parameterType.Type)) { InheritNullableStateOfTrackableStruct( @@ -2976,7 +3005,7 @@ private void VisitStatementsWithLocalFunctions(BoundBlock block) var symbol = variables[variables.RootSlot(slot)].Symbol; if (Symbol.IsCaptured(symbol, localFunc)) { - state[slot] = startingState[slot]; + SetState(ref state, slot, GetState(ref startingState, slot)); } }, _variables); @@ -3195,7 +3224,7 @@ private void DeclareLocal(LocalSymbol local) int slot = GetOrCreateSlot(local); if (slot > 0) { - this.State[slot] = GetDefaultState(ref this.State, slot); + SetState(ref this.State, slot, GetDefaultState(ref this.State, slot)); InheritDefaultState(GetDeclaredLocalResult(local).Type, slot); } } @@ -3558,7 +3587,7 @@ void setAnalyzedNullabilityAsContinuation( } } - this.State[slot] = resultState; + SetState(ref this.State, slot, resultState); } } @@ -3775,7 +3804,7 @@ int getOrCreateSlot(int containingSlot, Symbol symbol) if (slot >= 0 && !initializer.Initializers.IsEmpty) { - if (!initializer.Type.IsValueType && State[slot].MayBeNull()) + if (!initializer.Type.IsValueType && GetState(ref State, slot).MayBeNull()) { ReportDiagnostic(ErrorCode.WRN_NullReferenceInitializer, initializer.Syntax, symbol); } @@ -3874,7 +3903,7 @@ conversionCompletion is not null ? Debug.Assert(TypeSymbol.Equals(containingType, receiverResult.VisitResult.RValueType.Type, TypeCompareKind.IgnoreNullableModifiersForReferenceTypes)); Debug.Assert(TypeSymbol.Equals(containingType, receiverResult.LValueType.Type, TypeCompareKind.IgnoreNullableModifiersForReferenceTypes)); } -#endif +#endif return setUpdatedSymbol(node, containingType, reinferredMethod, argumentResults, visitArgumentsCompletion, delayCompletionForType); @@ -4443,7 +4472,7 @@ protected override void VisitBinaryOperatorChildren(ArrayBuilder operandType?.CanContainNull() == true; - private static void MarkSlotsAsNotNull(ArrayBuilder slots, ref LocalState stateToUpdate) + private void MarkSlotsAsNotNull(ArrayBuilder slots, ref LocalState stateToUpdate) { foreach (int slot in slots) { - stateToUpdate[slot] = NullableFlowState.NotNull; + SetState(ref stateToUpdate, slot, NullableFlowState.NotNull); } } @@ -4927,13 +4956,13 @@ private void LearnFromNonNullTest(BoundExpression expression, ref LocalState sta private void LearnFromNonNullTest(int slot, ref LocalState state) { - state[slot] = NullableFlowState.NotNull; + SetState(ref state, slot, NullableFlowState.NotNull); } private void LearnFromNullTest(BoundExpression expression, ref LocalState state) { // nothing to learn about a constant - if (expression.ConstantValue != null) + if (expression.ConstantValueOpt != null) return; // We should not blindly strip conversions here. Tracked by https://github.com/dotnet/roslyn/issues/36164 @@ -4952,10 +4981,10 @@ private void LearnFromNullTest(int slot, TypeSymbol? expressionType, ref LocalSt { if (slot > 0 && PossiblyNullableType(expressionType)) { - if (state[slot] == NullableFlowState.NotNull) + if (GetState(ref state, slot) == NullableFlowState.NotNull) { // Note: We leave a MaybeDefault state as-is - state[slot] = NullableFlowState.MaybeNull; + SetState(ref state, slot, NullableFlowState.MaybeNull); } if (markDependentSlotsNotNull) @@ -4984,7 +5013,7 @@ private void MarkDependentSlotsNotNull(int slot, TypeSymbol expressionType, ref int childSlot = GetOrCreateSlot(member, slot, forceSlotEvenIfEmpty: true, createIfMissing: false); if (childSlot > 0) { - state[childSlot] = NullableFlowState.NotNull; + SetState(ref state, childSlot, NullableFlowState.NotNull); MarkDependentSlotsNotNull(childSlot, member.GetTypeOrReturnType().Type, ref state, depth - 1); } } @@ -5087,7 +5116,7 @@ private static BoundExpression SkipReferenceConversions(BoundExpression possibly Unsplit(); LearnFromNullTest(leftOperand, ref this.State); - bool leftIsConstant = leftOperand.ConstantValue != null; + bool leftIsConstant = leftOperand.ConstantValueOpt != null; if (leftIsConstant) { SetUnreachable(); @@ -5242,7 +5271,7 @@ private void VisitConditionalAccess(BoundConditionalAccess node, out PossiblyCon _currentConditionalReceiverVisitResult = _visitResult; var previousConditionalAccessSlot = _lastConditionalAccessSlot; - if (receiver.ConstantValue is { IsNull: false }) + if (receiver.ConstantValueOpt is { IsNull: false }) { // Consider a scenario like `"a"?.M0(x = 1)?.M0(y = 1)`. // We can "know" that `.M0(x = 1)` was evaluated unconditionally but not `M0(y = 1)`. @@ -5799,13 +5828,13 @@ void learnFromEqualsMethodArguments(BoundExpression left, TypeWithState leftType { // comparing anything to a null literal gives maybe-null when true and not-null when false // comparing a maybe-null to a not-null gives us not-null when true, nothing learned when false - if (left.ConstantValue?.IsNull == true) + if (left.ConstantValueOpt?.IsNull == true) { Split(); LearnFromNullTest(right, ref StateWhenTrue); LearnFromNonNullTest(right, ref StateWhenFalse); } - else if (right.ConstantValue?.IsNull == true) + else if (right.ConstantValueOpt?.IsNull == true) { Split(); LearnFromNullTest(left, ref StateWhenTrue); @@ -5869,7 +5898,7 @@ private NullableFlowState LearnFromCompareExchangeMethod(in CompareExchangeInfo if (compareExchangeInfo.Arguments.Length != 3) { // This can occur if CompareExchange has optional arguments. - // Since none of the main runtimes have optional arguments, + // Since none of the main runtimes have optional arguments, // we bail to avoid an exception but don't bother actually calculating the FlowState. return NullableFlowState.NotNull; } @@ -5882,7 +5911,7 @@ private NullableFlowState LearnFromCompareExchangeMethod(in CompareExchangeInfo var comparand = compareExchangeInfo.Arguments[comparandIndex]; var valueFlowState = compareExchangeInfo.Results[valueIndex].RValueType.State; - if (comparand.ConstantValue?.IsNull == true) + if (comparand.ConstantValueOpt?.IsNull == true) { // If location contained a null, then the write `location = value` definitely occurred } @@ -6400,7 +6429,7 @@ void markMembersAsNotNull(int receiverSlot, TypeSymbol type, string memberName, if (GetOrCreateSlot(member, receiverSlot) is int memberSlot && memberSlot > 0) { - state[memberSlot] = NullableFlowState.NotNull; + SetState(ref state, memberSlot, NullableFlowState.NotNull); } break; case SymbolKind.Event: @@ -7055,7 +7084,7 @@ private static NullableAnnotation GetNullableAnnotation(BoundExpression expr) case BoundKind.DefaultLiteral: case BoundKind.DefaultExpression: case BoundKind.Literal: - return expr.ConstantValue == ConstantValue.NotAvailable || !expr.ConstantValue.IsNull || expr.IsSuppressed ? NullableAnnotation.NotAnnotated : NullableAnnotation.Annotated; + return expr.ConstantValueOpt == ConstantValue.NotAvailable || !expr.ConstantValueOpt.IsNull || expr.IsSuppressed ? NullableAnnotation.NotAnnotated : NullableAnnotation.Annotated; case BoundKind.ExpressionWithNullability: return ((BoundExpressionWithNullability)expr).NullableAnnotation; case BoundKind.MethodGroup: @@ -7250,7 +7279,7 @@ private static bool UseExpressionForConversion([NotNullWhen(true)] BoundExpressi { return false; } - if (value.Type is null || value.Type.IsDynamic() || value.ConstantValue != null) + if (value.Type is null || value.Type.IsDynamic() || value.ConstantValueOpt != null) { return true; } @@ -7268,9 +7297,9 @@ private static bool UseExpressionForConversion([NotNullWhen(true)] BoundExpressi /// private TypeWithState GetAdjustedResult(TypeWithState type, int slot) { - if (this.State.HasValue(slot)) + if (slot > 0) { - NullableFlowState state = this.State[slot]; + NullableFlowState state = GetState(ref this.State, slot); return TypeWithState.Create(type.Type, state); } @@ -7542,7 +7571,7 @@ private void VisitTupleExpression(BoundTupleExpression node) int slot = GetOrCreatePlaceholderSlot(node); if (slot > 0) { - this.State[slot] = NullableFlowState.NotNull; + SetState(ref this.State, slot, NullableFlowState.NotNull); TrackNullableStateOfTupleElements(slot, tupleOpt, arguments, elementTypes, argsToParamsOpt: default, useRestField: false); } @@ -7676,7 +7705,7 @@ void trackConvertedValue(FieldSymbol targetField, Conversion conversion, FieldSy int targetFieldSlot = GetOrCreateSlot(targetField, slot); if (targetFieldSlot > 0) { - this.State[targetFieldSlot] = NullableFlowState.NotNull; + SetState(ref this.State, targetFieldSlot, NullableFlowState.NotNull); int valueFieldSlot = GetOrCreateSlot(valueField, valueSlot); if (valueFieldSlot > 0) { @@ -7693,7 +7722,7 @@ void trackConvertedValue(FieldSymbol targetField, Conversion conversion, FieldSy int targetFieldSlot = GetOrCreateSlot(targetField, slot); if (targetFieldSlot > 0) { - this.State[targetFieldSlot] = NullableFlowState.NotNull; + SetState(ref this.State, targetFieldSlot, NullableFlowState.NotNull); int valueFieldSlot = GetOrCreateSlot(valueField, valueSlot); if (valueFieldSlot > 0) { @@ -7720,7 +7749,7 @@ void trackConvertedValue(FieldSymbol targetField, Conversion conversion, FieldSy int targetFieldSlot = GetOrCreateSlot(targetField, slot); if (targetFieldSlot > 0) { - this.State[targetFieldSlot] = convertedType.State; + SetState(ref this.State, targetFieldSlot, convertedType.State); } } break; @@ -8387,7 +8416,7 @@ void visitHandlerConstruction(InterpolatedStringHandlerData handlerData) VisitRvalue(handlerData.Construction); #if DEBUG _completingTargetTypedExpression = save_completingTargetTypedExpression; -#endif +#endif } } @@ -9852,9 +9881,9 @@ private Symbol VisitMemberAccess(BoundExpression node, BoundExpression? receiver if (PossiblyNullableType(resultType.Type)) { int slot = MakeMemberSlot(receiverOpt, member); - if (this.State.HasValue(slot)) + if (slot > 0) { - var state = this.State[slot]; + var state = GetState(ref this.State, slot); resultType = TypeWithState.Create(resultType.Type, state); } } @@ -9866,7 +9895,7 @@ private Symbol VisitMemberAccess(BoundExpression node, BoundExpression? receiver if (containingSlot > 0) { Split(); - this.StateWhenTrue[containingSlot] = NullableFlowState.NotNull; + SetState(ref this.StateWhenTrue, containingSlot, NullableFlowState.NotNull); } } @@ -9935,7 +9964,7 @@ protected override void VisitForEachExpression(BoundForEachStatement node) // 6. The target framework's System.String doesn't implement IEnumerable. This is a compat case: System.String normally // does implement IEnumerable, but there are certain target frameworks where this isn't the case. The compiler will // still emit code for foreach in these scenarios. - // 7. The collection type implements the GetEnumerator pattern via an extension GetEnumerator. For this, there will be + // 7. The collection type implements the GetEnumerator pattern via an extension GetEnumerator. For this, there will be // conversion to the parameter of the extension method. // 8. Some binding error occurred, and some other error has already been reported. Usually this doesn't have any kind // of conversion on top, but if there was an explicit conversion in code then we could get past the initial check @@ -10186,7 +10215,7 @@ public override void VisitForEachIterationVariables(BoundForEachStatement node) int slot = GetOrCreateSlot(iterationVariable); if (slot > 0) { - this.State[slot] = state; + SetState(ref this.State, slot, state); } } @@ -10526,7 +10555,7 @@ private TypeWithState InferResultNullabilityOfBinaryLogicalOperator(BoundExpress int slot = GetOrCreatePlaceholderSlot(node); if (slot > 0) { - this.State[slot] = NullableFlowState.NotNull; + SetState(ref this.State, slot, NullableFlowState.NotNull); InheritNullableStateOfTrackableStruct(type, slot, valueSlot: -1, isDefaultValue: true); } } @@ -10627,7 +10656,7 @@ private TypeWithState InferResultNullabilityOfBinaryLogicalOperator(BoundExpress { Debug.Assert(!IsConditionalState); var result = base.VisitLiteral(node); - SetResultType(node, TypeWithState.Create(node.Type, node.Type?.CanContainNull() != false && node.ConstantValue?.IsNull == true ? NullableFlowState.MaybeDefault : NullableFlowState.NotNull)); + SetResultType(node, TypeWithState.Create(node.Type, node.Type?.CanContainNull() != false && node.ConstantValueOpt?.IsNull == true ? NullableFlowState.MaybeDefault : NullableFlowState.NotNull)); return result; } @@ -10731,12 +10760,11 @@ private TypeWithState InferResultNullabilityOfBinaryLogicalOperator(BoundExpress } VisitRvalue(node.Argument); // https://github.com/dotnet/roslyn/issues/31018: Check for delegate mismatch. - if (node.Argument.ConstantValue?.IsNull != true + if (node.Argument.ConstantValueOpt?.IsNull != true && MakeMemberSlot(receiverOpt, @event) is > 0 and var memberSlot) { - this.State[memberSlot] = node.IsAddition - ? this.State[memberSlot].Meet(ResultType.State) - : NullableFlowState.MaybeNull; + SetState(ref this.State, memberSlot, + node.IsAddition ? GetState(ref this.State, memberSlot).Meet(ResultType.State) : NullableFlowState.MaybeNull); } SetNotNullResult(node); // https://github.com/dotnet/roslyn/issues/29969 Review whether this is the correct result return null; @@ -11050,7 +11078,7 @@ protected override void VisitCatchBlock(BoundCatchBlock node, ref LocalState fin { int slot = GetOrCreateSlot(local); if (slot > 0) - this.State[slot] = NullableFlowState.NotNull; + SetState(ref this.State, slot, NullableFlowState.NotNull); } } @@ -11312,27 +11340,48 @@ public static LocalState UnreachableState(Variables variables) return CreateReachableOrUnreachableState(variables, reachable: false); } + public static LocalState ReachableStateWithNotNulls(Variables variables) + { + var container = variables.Container is null ? + null : + new Boxed(ReachableStateWithNotNulls(variables.Container)); + + int capacity = variables.NextAvailableIndex; + return new LocalState(variables.Id, container, createBitVectorWithNotNulls(capacity, reachable: true)); + + static BitVector createBitVectorWithNotNulls(int capacity, bool reachable) + { + BitVector state = BitVector.Create(capacity * 2); + state[0] = reachable; + + for (int i = 1; i < capacity; i++) + { + var index = i * 2; + state[index] = true; + state[index + 1] = true; + } + return state; + } + } + private static LocalState CreateReachableOrUnreachableState(Variables variables, bool reachable) { var container = variables.Container is null ? null : new Boxed(CreateReachableOrUnreachableState(variables.Container, reachable)); - int capacity = reachable ? variables.NextAvailableIndex : 1; - return new LocalState(variables.Id, container, CreateBitVector(capacity, reachable)); + + return new LocalState(variables.Id, container, CreateBitVector(reachable)); } public LocalState CreateNestedMethodState(Variables variables) { Debug.Assert(Id == variables.Container!.Id); - return new LocalState(variables.Id, container: new Boxed(this), CreateBitVector(capacity: variables.NextAvailableIndex, reachable: true)); + return new LocalState(variables.Id, container: new Boxed(this), CreateBitVector(reachable: true)); } - private static BitVector CreateBitVector(int capacity, bool reachable) + private static BitVector CreateBitVector(bool reachable) { - if (capacity < 1) - capacity = 1; - - BitVector state = BitVector.Create(capacity * 2); + BitVector state = BitVector.Create(2); state[0] = reachable; return state; } @@ -11351,73 +11400,79 @@ public bool HasVariable(int slot) return false; } (int id, int index) = Variables.DeconstructSlot(slot); - return HasVariable(id, index); - } + return hasVariableCore(ref this, id, index); - private bool HasVariable(int id, int index) - { - if (Id > id) - { - return _container!.Value.HasValue(id, index); - } - else + bool hasVariableCore(ref LocalState state, int id, int index) { - return Id == id; + if (state.Id > id) + { + return hasVariableCore(ref state._container!.Value, id, index); + } + else + { + return state.Id == id; + } } } - public bool HasValue(int slot) + public void NormalizeIfNeeded(int slot, NullableWalker walker, Variables variables, bool useNotNullsAsDefault = false) { - if (slot <= 0) - { - return false; - } - (int id, int index) = Variables.DeconstructSlot(slot); - return HasValue(id, index); - } + if (!hasValue(ref this, slot)) + Normalize(walker, variables, useNotNullsAsDefault); - private bool HasValue(int id, int index) - { - if (Id != id) + static bool hasValue(ref LocalState state, int slot) { - Debug.Assert(Id > id); - return _container!.Value.HasValue(id, index); + if (slot <= 0) + { + return false; + } + (int id, int index) = Variables.DeconstructSlot(slot); + return hasValueCore(ref state, id, index); } - else + + static bool hasValueCore(ref LocalState state, int id, int index) { - return index < Capacity; + if (state.Id != id) + { + Debug.Assert(state.Id > id); + return hasValueCore(ref state._container!.Value, id, index); + } + else + { + return index < state.Capacity; + } } } - public void Normalize(NullableWalker walker, Variables variables) + public void Normalize(NullableWalker walker, Variables variables, bool useNotNullsAsDefault = false) { if (Id != variables.Id) { Debug.Assert(Id < variables.Id); - Normalize(walker, variables.Container!); + Normalize(walker, variables.Container!, useNotNullsAsDefault); } else { - _container?.Value.Normalize(walker, variables.Container!); + _container?.Value.Normalize(walker, variables.Container!, useNotNullsAsDefault); int start = Capacity; EnsureCapacity(variables.NextAvailableIndex); - Populate(walker, start); + Populate(walker, start, useNotNullsAsDefault); } } public void PopulateAll(NullableWalker walker) { _container?.Value.PopulateAll(walker); - Populate(walker, start: 1); + Populate(walker, start: 1, useNotNullsAsDefault: false); } - private void Populate(NullableWalker walker, int start) + private void Populate(NullableWalker walker, int start, bool useNotNullsAsDefault) { int capacity = Capacity; for (int index = start; index < capacity; index++) { int slot = Variables.ConstructSlot(Id, index); - SetValue(Id, index, walker.GetDefaultState(ref this, slot)); + SetValue(Id, index, useNotNullsAsDefault ? NullableFlowState.NotNull : walker.GetDefaultState(ref this, slot)); } } @@ -11442,22 +11497,25 @@ private NullableFlowState GetValue(int id, int index) Debug.Assert(Id > id); return _container!.Value.GetValue(id, index); } - else + return GetValue(index); + } + + private NullableFlowState GetValue(int index) + { + if (!this.Reachable) { - if (index < Capacity && this.Reachable) - { - index *= 2; - var result = (_state[index + 1], _state[index]) switch - { - (false, false) => NullableFlowState.NotNull, - (false, true) => NullableFlowState.MaybeNull, - (true, false) => throw ExceptionUtilities.UnexpectedValue(index), - (true, true) => NullableFlowState.MaybeDefault - }; - return result; - } return NullableFlowState.NotNull; } + Debug.Assert(index < Capacity); + index *= 2; + var result = (_state[index], _state[index + 1]) switch + { + (false, false) => throw ExceptionUtilities.Unreachable(), + (true, false) => NullableFlowState.MaybeNull, + (false, true) => NullableFlowState.MaybeDefault, + (true, true) => NullableFlowState.NotNull + }; + return result; } private void SetValue(int id, int index, NullableFlowState value) @@ -11469,14 +11527,25 @@ private void SetValue(int id, int index, NullableFlowState value) } else { - // No states should be modified in unreachable code, as there is only one unreachable state. - if (!this.Reachable) return; - index *= 2; - _state[index] = (value != NullableFlowState.NotNull); - _state[index + 1] = (value == NullableFlowState.MaybeDefault); + SetValue(index, value); } } + private void SetValue(int index, NullableFlowState value) + { + // No states should be modified in unreachable code, as there is only one unreachable state. + if (!this.Reachable) return; + index *= 2; + + (_state[index], _state[index + 1]) = value switch + { + NullableFlowState.MaybeNull => (true, false), + NullableFlowState.MaybeDefault => (false, true), + NullableFlowState.NotNull => (true, true), + _ => throw ExceptionUtilities.Unreachable() + }; + } + internal void ForEach(Action action, TArg arg) { _container?.Value.ForEach(action, arg); @@ -11509,31 +11578,53 @@ public LocalState Clone() public bool Join(in LocalState other) { Debug.Assert(Id == other.Id); - bool result = false; + bool hasChanged = false; if (_container is { } && _container.Value.Join(in other._container!.Value)) { - result = true; + hasChanged = true; } - if (_state.UnionWith(in other._state)) + + Debug.Assert(_state.Capacity == other._state.Capacity); + var oldReachable = Reachable; + var newReachable = oldReachable | other.Reachable; + _state[0] = newReachable; + hasChanged |= (oldReachable != newReachable); + + for (int i = 1; i < Capacity; i++) { - result = true; + var oldValue = GetValue(i); + var newValue = oldValue.Join(other.GetValue(i)); + SetValue(i, newValue); + hasChanged |= (oldValue != newValue); } - return result; + + return hasChanged; } public bool Meet(in LocalState other) { Debug.Assert(Id == other.Id); - bool result = false; + bool hasChanged = false; if (_container is { } && _container.Value.Meet(in other._container!.Value)) { - result = true; + hasChanged = true; } - if (_state.IntersectWith(in other._state)) + + Debug.Assert(_state.Capacity == other._state.Capacity); + var oldReachable = Reachable; + var newReachable = oldReachable & other.Reachable; + _state[0] = newReachable; + hasChanged |= (oldReachable != newReachable); + + for (int i = 1; i < Capacity; i++) { - result = true; + var oldValue = GetValue(i); + var newValue = oldValue.Meet(other.GetValue(i)); + SetValue(i, newValue); + hasChanged |= (oldValue != newValue); } - return result; + + return hasChanged; } internal string GetDebuggerDisplay() @@ -11543,7 +11634,10 @@ internal string GetDebuggerDisplay() builder.Append(" "); int n = Math.Min(Capacity, 8); for (int i = n - 1; i >= 0; i--) - builder.Append(_state[i * 2] ? '?' : '!'); + { + var mayBeNull = GetValue(i) is NullableFlowState.MaybeNull or NullableFlowState.MaybeDefault; + builder.Append(mayBeNull ? '?' : '!'); + } return pooledBuilder.ToStringAndFree(); } diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker_Patterns.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker_Patterns.cs index 7cbb11cf984ad..2159a4fcbbb37 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker_Patterns.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker_Patterns.cs @@ -142,7 +142,7 @@ private void LearnFromAnyNullPatterns( switch (pattern) { case BoundConstantPattern cp: - bool isExplicitNullCheck = cp.Value.ConstantValue == ConstantValue.Null; + bool isExplicitNullCheck = cp.Value.ConstantValueOpt == ConstantValue.Null; if (isExplicitNullCheck) { // Since we're not branching on this null test here, we just infer the top level @@ -428,7 +428,7 @@ public PossiblyConditionalState Clone() } Debug.Assert(!IsConditionalState); Unsplit(); - State[outputSlot] = NullableFlowState.NotNull; + SetState(ref State, outputSlot, NullableFlowState.NotNull); addToTempMap(output, outputSlot, e.Type); break; } @@ -519,7 +519,7 @@ public PossiblyConditionalState Clone() var outputSlot = makeDagTempSlot(type, output); Debug.Assert(outputSlot > 0); addToTempMap(output, outputSlot, type.Type); - this.State[outputSlot] = NullableFlowState.NotNull; // Slice value is assumed to be never null + SetState(ref this.State, outputSlot, NullableFlowState.NotNull); // Slice value is assumed to be never null break; } case BoundDagAssignmentEvaluation e: @@ -549,7 +549,7 @@ public PossiblyConditionalState Clone() gotoNode(p.WhenFalse, this.StateWhenFalse, nodeBelievedReachable); break; case BoundDagNonNullTest t: - var inputMaybeNull = this.StateWhenTrue[inputSlot].MayBeNull(); + var inputMaybeNull = GetState(ref this.StateWhenTrue, inputSlot).MayBeNull(); if (inputSlot > 0) { @@ -622,7 +622,7 @@ public PossiblyConditionalState Clone() if (foundTemp) // in erroneous programs, we might not have seen a temp defined. { var (tempSlot, tempType) = tempSlotAndType; - var tempState = this.State[tempSlot]; + var tempState = GetState(ref this.State, tempSlot); if (variableAccess is BoundLocal { LocalSymbol: SourceLocalSymbol local } boundLocal) { var value = TypeWithState.Create(tempType, tempState); @@ -647,7 +647,7 @@ public PossiblyConditionalState Clone() } } - if (w.WhenExpression != null && w.WhenExpression.ConstantValue != ConstantValue.True) + if (w.WhenExpression != null && w.WhenExpression.ConstantValueOpt != ConstantValue.True) { VisitCondition(w.WhenExpression); Debug.Assert(this.IsConditionalState); diff --git a/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs b/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs index 4551d29aba12c..8691b920e5724 100644 --- a/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs @@ -173,6 +173,7 @@ internal enum BoundKind : byte LoweredConditionalAccess, ConditionalReceiver, ComplexConditionalReceiver, + ComplexReceiver, MethodGroup, PropertyGroup, Call, @@ -510,38 +511,38 @@ public BoundCapturedReceiverPlaceholder Update(BoundExpression receiver, uint lo internal sealed partial class BoundDeconstructValuePlaceholder : BoundValuePlaceholderBase { - public BoundDeconstructValuePlaceholder(SyntaxNode syntax, Symbol? variableSymbol, uint valEscape, TypeSymbol type, bool hasErrors) + public BoundDeconstructValuePlaceholder(SyntaxNode syntax, Symbol? variableSymbol, bool isDiscardExpression, TypeSymbol type, bool hasErrors) : base(BoundKind.DeconstructValuePlaceholder, syntax, type, hasErrors) { RoslynDebug.Assert(type is object, "Field 'type' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); this.VariableSymbol = variableSymbol; - this.ValEscape = valEscape; + this.IsDiscardExpression = isDiscardExpression; } - public BoundDeconstructValuePlaceholder(SyntaxNode syntax, Symbol? variableSymbol, uint valEscape, TypeSymbol type) + public BoundDeconstructValuePlaceholder(SyntaxNode syntax, Symbol? variableSymbol, bool isDiscardExpression, TypeSymbol type) : base(BoundKind.DeconstructValuePlaceholder, syntax, type) { RoslynDebug.Assert(type is object, "Field 'type' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); this.VariableSymbol = variableSymbol; - this.ValEscape = valEscape; + this.IsDiscardExpression = isDiscardExpression; } public new TypeSymbol Type => base.Type!; public Symbol? VariableSymbol { get; } - public uint ValEscape { get; } + public bool IsDiscardExpression { get; } [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitDeconstructValuePlaceholder(this); - public BoundDeconstructValuePlaceholder Update(Symbol? variableSymbol, uint valEscape, TypeSymbol type) + public BoundDeconstructValuePlaceholder Update(Symbol? variableSymbol, bool isDiscardExpression, TypeSymbol type) { - if (!Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(variableSymbol, this.VariableSymbol) || valEscape != this.ValEscape || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything)) + if (!Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(variableSymbol, this.VariableSymbol) || isDiscardExpression != this.IsDiscardExpression || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything)) { - var result = new BoundDeconstructValuePlaceholder(this.Syntax, variableSymbol, valEscape, type, this.HasErrors); + var result = new BoundDeconstructValuePlaceholder(this.Syntax, variableSymbol, isDiscardExpression, type, this.HasErrors); result.CopyAttributes(this); return result; } @@ -586,29 +587,26 @@ public BoundTupleOperandPlaceholder Update(TypeSymbol type) internal sealed partial class BoundAwaitableValuePlaceholder : BoundValuePlaceholderBase { - public BoundAwaitableValuePlaceholder(SyntaxNode syntax, uint valEscape, TypeSymbol? type, bool hasErrors) + public BoundAwaitableValuePlaceholder(SyntaxNode syntax, TypeSymbol? type, bool hasErrors) : base(BoundKind.AwaitableValuePlaceholder, syntax, type, hasErrors) { - this.ValEscape = valEscape; } - public BoundAwaitableValuePlaceholder(SyntaxNode syntax, uint valEscape, TypeSymbol? type) + public BoundAwaitableValuePlaceholder(SyntaxNode syntax, TypeSymbol? type) : base(BoundKind.AwaitableValuePlaceholder, syntax, type) { - this.ValEscape = valEscape; } public new TypeSymbol? Type => base.Type; - public uint ValEscape { get; } [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitAwaitableValuePlaceholder(this); - public BoundAwaitableValuePlaceholder Update(uint valEscape, TypeSymbol? type) + public BoundAwaitableValuePlaceholder Update(TypeSymbol? type) { - if (valEscape != this.ValEscape || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything)) + if (!TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything)) { - var result = new BoundAwaitableValuePlaceholder(this.Syntax, valEscape, type, this.HasErrors); + var result = new BoundAwaitableValuePlaceholder(this.Syntax, type, this.HasErrors); result.CopyAttributes(this); return result; } @@ -726,38 +724,35 @@ public BoundImplicitIndexerValuePlaceholder Update(TypeSymbol type) internal sealed partial class BoundImplicitIndexerReceiverPlaceholder : BoundValuePlaceholderBase { - public BoundImplicitIndexerReceiverPlaceholder(SyntaxNode syntax, uint valEscape, bool isEquivalentToThisReference, TypeSymbol type, bool hasErrors) + public BoundImplicitIndexerReceiverPlaceholder(SyntaxNode syntax, bool isEquivalentToThisReference, TypeSymbol type, bool hasErrors) : base(BoundKind.ImplicitIndexerReceiverPlaceholder, syntax, type, hasErrors) { RoslynDebug.Assert(type is object, "Field 'type' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); - this.ValEscape = valEscape; this.IsEquivalentToThisReference = isEquivalentToThisReference; } - public BoundImplicitIndexerReceiverPlaceholder(SyntaxNode syntax, uint valEscape, bool isEquivalentToThisReference, TypeSymbol type) + public BoundImplicitIndexerReceiverPlaceholder(SyntaxNode syntax, bool isEquivalentToThisReference, TypeSymbol type) : base(BoundKind.ImplicitIndexerReceiverPlaceholder, syntax, type) { RoslynDebug.Assert(type is object, "Field 'type' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); - this.ValEscape = valEscape; this.IsEquivalentToThisReference = isEquivalentToThisReference; } public new TypeSymbol Type => base.Type!; - public uint ValEscape { get; } public override bool IsEquivalentToThisReference { get; } [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitImplicitIndexerReceiverPlaceholder(this); - public BoundImplicitIndexerReceiverPlaceholder Update(uint valEscape, bool isEquivalentToThisReference, TypeSymbol type) + public BoundImplicitIndexerReceiverPlaceholder Update(bool isEquivalentToThisReference, TypeSymbol type) { - if (valEscape != this.ValEscape || isEquivalentToThisReference != this.IsEquivalentToThisReference || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything)) + if (isEquivalentToThisReference != this.IsEquivalentToThisReference || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything)) { - var result = new BoundImplicitIndexerReceiverPlaceholder(this.Syntax, valEscape, isEquivalentToThisReference, type, this.HasErrors); + var result = new BoundImplicitIndexerReceiverPlaceholder(this.Syntax, isEquivalentToThisReference, type, this.HasErrors); result.CopyAttributes(this); return result; } @@ -767,35 +762,32 @@ public BoundImplicitIndexerReceiverPlaceholder Update(uint valEscape, bool isEqu internal sealed partial class BoundListPatternReceiverPlaceholder : BoundEarlyValuePlaceholderBase { - public BoundListPatternReceiverPlaceholder(SyntaxNode syntax, uint valEscape, TypeSymbol type, bool hasErrors) + public BoundListPatternReceiverPlaceholder(SyntaxNode syntax, TypeSymbol type, bool hasErrors) : base(BoundKind.ListPatternReceiverPlaceholder, syntax, type, hasErrors) { RoslynDebug.Assert(type is object, "Field 'type' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); - this.ValEscape = valEscape; } - public BoundListPatternReceiverPlaceholder(SyntaxNode syntax, uint valEscape, TypeSymbol type) + public BoundListPatternReceiverPlaceholder(SyntaxNode syntax, TypeSymbol type) : base(BoundKind.ListPatternReceiverPlaceholder, syntax, type) { RoslynDebug.Assert(type is object, "Field 'type' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); - this.ValEscape = valEscape; } public new TypeSymbol Type => base.Type!; - public uint ValEscape { get; } [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitListPatternReceiverPlaceholder(this); - public BoundListPatternReceiverPlaceholder Update(uint valEscape, TypeSymbol type) + public BoundListPatternReceiverPlaceholder Update(TypeSymbol type) { - if (valEscape != this.ValEscape || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything)) + if (!TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything)) { - var result = new BoundListPatternReceiverPlaceholder(this.Syntax, valEscape, type, this.HasErrors); + var result = new BoundListPatternReceiverPlaceholder(this.Syntax, type, this.HasErrors); result.CopyAttributes(this); return result; } @@ -840,35 +832,32 @@ public BoundListPatternIndexPlaceholder Update(TypeSymbol type) internal sealed partial class BoundSlicePatternReceiverPlaceholder : BoundEarlyValuePlaceholderBase { - public BoundSlicePatternReceiverPlaceholder(SyntaxNode syntax, uint valEscape, TypeSymbol type, bool hasErrors) + public BoundSlicePatternReceiverPlaceholder(SyntaxNode syntax, TypeSymbol type, bool hasErrors) : base(BoundKind.SlicePatternReceiverPlaceholder, syntax, type, hasErrors) { RoslynDebug.Assert(type is object, "Field 'type' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); - this.ValEscape = valEscape; } - public BoundSlicePatternReceiverPlaceholder(SyntaxNode syntax, uint valEscape, TypeSymbol type) + public BoundSlicePatternReceiverPlaceholder(SyntaxNode syntax, TypeSymbol type) : base(BoundKind.SlicePatternReceiverPlaceholder, syntax, type) { RoslynDebug.Assert(type is object, "Field 'type' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); - this.ValEscape = valEscape; } public new TypeSymbol Type => base.Type!; - public uint ValEscape { get; } [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitSlicePatternReceiverPlaceholder(this); - public BoundSlicePatternReceiverPlaceholder Update(uint valEscape, TypeSymbol type) + public BoundSlicePatternReceiverPlaceholder Update(TypeSymbol type) { - if (valEscape != this.ValEscape || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything)) + if (!TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything)) { - var result = new BoundSlicePatternReceiverPlaceholder(this.Syntax, valEscape, type, this.HasErrors); + var result = new BoundSlicePatternReceiverPlaceholder(this.Syntax, type, this.HasErrors); result.CopyAttributes(this); return result; } @@ -1194,7 +1183,7 @@ public BoundUnaryOperator(SyntaxNode syntax, UnaryOperatorKind operatorKind, Bou public new TypeSymbol Type => base.Type!; public UnaryOperatorKind OperatorKind { get; } public BoundExpression Operand { get; } - public ConstantValue? ConstantValueOpt { get; } + public override ConstantValue? ConstantValueOpt { get; } public MethodSymbol? MethodOpt { get; } public TypeSymbol? ConstrainedToTypeOpt { get; } public override LookupResultKind ResultKind { get; } @@ -1977,7 +1966,7 @@ public BoundUnconvertedConditionalOperator(SyntaxNode syntax, BoundExpression co public BoundExpression Condition { get; } public BoundExpression Consequence { get; } public BoundExpression Alternative { get; } - public ConstantValue? ConstantValueOpt { get; } + public override ConstantValue? ConstantValueOpt { get; } public ErrorCode NoCommonTypeError { get; } [DebuggerStepThrough] @@ -2020,7 +2009,7 @@ public BoundConditionalOperator(SyntaxNode syntax, bool isRef, BoundExpression c public BoundExpression Condition { get; } public BoundExpression Consequence { get; } public BoundExpression Alternative { get; } - public ConstantValue? ConstantValueOpt { get; } + public override ConstantValue? ConstantValueOpt { get; } public TypeSymbol? NaturalTypeOpt { get; } public bool WasTargetTyped { get; } @@ -2567,7 +2556,7 @@ public BoundDefaultExpression(SyntaxNode syntax, BoundTypeExpression? targetType public new TypeSymbol Type => base.Type!; public BoundTypeExpression? TargetType { get; } - public ConstantValue? ConstantValueOpt { get; } + public override ConstantValue? ConstantValueOpt { get; } [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitDefaultExpression(this); @@ -2671,7 +2660,7 @@ public BoundSizeOfOperator(SyntaxNode syntax, BoundTypeExpression sourceType, Co public new TypeSymbol Type => base.Type!; public BoundTypeExpression SourceType { get; } - public ConstantValue? ConstantValueOpt { get; } + public override ConstantValue? ConstantValueOpt { get; } [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitSizeOfOperator(this); @@ -2713,7 +2702,7 @@ public BoundConversion(SyntaxNode syntax, BoundExpression operand, Conversion co public bool IsBaseConversion { get; } public bool Checked { get; } public bool ExplicitCastInCode { get; } - public ConstantValue? ConstantValueOpt { get; } + public override ConstantValue? ConstantValueOpt { get; } public ConversionGroup? ConversionGroupOpt { get; } public ImmutableArray OriginalUserDefinedConversionsOpt { get; } @@ -3043,7 +3032,7 @@ public BoundStepThroughSequencePoint Update(TextSpan span) internal sealed partial class BoundBlock : BoundStatementList { - public BoundBlock(SyntaxNode syntax, ImmutableArray locals, ImmutableArray localFunctions, ImmutableArray statements, bool hasErrors = false) + public BoundBlock(SyntaxNode syntax, ImmutableArray locals, ImmutableArray localFunctions, bool hasUnsafeModifier, ImmutableArray statements, bool hasErrors = false) : base(BoundKind.Block, syntax, statements, hasErrors || statements.HasErrors()) { @@ -3053,19 +3042,21 @@ public BoundBlock(SyntaxNode syntax, ImmutableArray locals, Immutab this.Locals = locals; this.LocalFunctions = localFunctions; + this.HasUnsafeModifier = hasUnsafeModifier; } public ImmutableArray Locals { get; } public ImmutableArray LocalFunctions { get; } + public bool HasUnsafeModifier { get; } [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitBlock(this); - public BoundBlock Update(ImmutableArray locals, ImmutableArray localFunctions, ImmutableArray statements) + public BoundBlock Update(ImmutableArray locals, ImmutableArray localFunctions, bool hasUnsafeModifier, ImmutableArray statements) { - if (locals != this.Locals || localFunctions != this.LocalFunctions || statements != this.Statements) + if (locals != this.Locals || localFunctions != this.LocalFunctions || hasUnsafeModifier != this.HasUnsafeModifier || statements != this.Statements) { - var result = new BoundBlock(this.Syntax, locals, localFunctions, statements, this.HasErrors); + var result = new BoundBlock(this.Syntax, locals, localFunctions, hasUnsafeModifier, statements, this.HasErrors); result.CopyAttributes(this); return result; } @@ -4045,7 +4036,7 @@ public BoundLiteral(SyntaxNode syntax, ConstantValue? constantValueOpt, TypeSymb this.ConstantValueOpt = constantValueOpt; } - public ConstantValue? ConstantValueOpt { get; } + public override ConstantValue? ConstantValueOpt { get; } [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitLiteral(this); @@ -4267,7 +4258,7 @@ public BoundLocal(SyntaxNode syntax, LocalSymbol localSymbol, BoundLocalDeclarat public new TypeSymbol Type => base.Type!; public LocalSymbol LocalSymbol { get; } public BoundLocalDeclarationKind DeclarationKind { get; } - public ConstantValue? ConstantValueOpt { get; } + public override ConstantValue? ConstantValueOpt { get; } public bool IsNullableUnknown { get; } [DebuggerStepThrough] @@ -5695,7 +5686,7 @@ public BoundConditionalAccess Update(BoundExpression receiver, BoundExpression a internal sealed partial class BoundLoweredConditionalAccess : BoundExpression { - public BoundLoweredConditionalAccess(SyntaxNode syntax, BoundExpression receiver, MethodSymbol? hasValueMethodOpt, BoundExpression whenNotNull, BoundExpression? whenNullOpt, int id, TypeSymbol type, bool hasErrors = false) + public BoundLoweredConditionalAccess(SyntaxNode syntax, BoundExpression receiver, MethodSymbol? hasValueMethodOpt, BoundExpression whenNotNull, BoundExpression? whenNullOpt, int id, bool forceCopyOfNullableValueType, TypeSymbol type, bool hasErrors = false) : base(BoundKind.LoweredConditionalAccess, syntax, type, hasErrors || receiver.HasErrors() || whenNotNull.HasErrors() || whenNullOpt.HasErrors()) { @@ -5708,6 +5699,7 @@ public BoundLoweredConditionalAccess(SyntaxNode syntax, BoundExpression receiver this.WhenNotNull = whenNotNull; this.WhenNullOpt = whenNullOpt; this.Id = id; + this.ForceCopyOfNullableValueType = forceCopyOfNullableValueType; } public new TypeSymbol Type => base.Type!; @@ -5716,15 +5708,16 @@ public BoundLoweredConditionalAccess(SyntaxNode syntax, BoundExpression receiver public BoundExpression WhenNotNull { get; } public BoundExpression? WhenNullOpt { get; } public int Id { get; } + public bool ForceCopyOfNullableValueType { get; } [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitLoweredConditionalAccess(this); - public BoundLoweredConditionalAccess Update(BoundExpression receiver, MethodSymbol? hasValueMethodOpt, BoundExpression whenNotNull, BoundExpression? whenNullOpt, int id, TypeSymbol type) + public BoundLoweredConditionalAccess Update(BoundExpression receiver, MethodSymbol? hasValueMethodOpt, BoundExpression whenNotNull, BoundExpression? whenNullOpt, int id, bool forceCopyOfNullableValueType, TypeSymbol type) { - if (receiver != this.Receiver || !Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(hasValueMethodOpt, this.HasValueMethodOpt) || whenNotNull != this.WhenNotNull || whenNullOpt != this.WhenNullOpt || id != this.Id || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything)) + if (receiver != this.Receiver || !Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(hasValueMethodOpt, this.HasValueMethodOpt) || whenNotNull != this.WhenNotNull || whenNullOpt != this.WhenNullOpt || id != this.Id || forceCopyOfNullableValueType != this.ForceCopyOfNullableValueType || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything)) { - var result = new BoundLoweredConditionalAccess(this.Syntax, receiver, hasValueMethodOpt, whenNotNull, whenNullOpt, id, type, this.HasErrors); + var result = new BoundLoweredConditionalAccess(this.Syntax, receiver, hasValueMethodOpt, whenNotNull, whenNullOpt, id, forceCopyOfNullableValueType, type, this.HasErrors); result.CopyAttributes(this); return result; } @@ -5803,6 +5796,39 @@ public BoundComplexConditionalReceiver Update(BoundExpression valueTypeReceiver, } } + internal sealed partial class BoundComplexReceiver : BoundExpression + { + public BoundComplexReceiver(SyntaxNode syntax, BoundExpression valueTypeReceiver, BoundExpression referenceTypeReceiver, TypeSymbol type, bool hasErrors = false) + : base(BoundKind.ComplexReceiver, syntax, type, hasErrors || valueTypeReceiver.HasErrors() || referenceTypeReceiver.HasErrors()) + { + + RoslynDebug.Assert(valueTypeReceiver is object, "Field 'valueTypeReceiver' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); + RoslynDebug.Assert(referenceTypeReceiver is object, "Field 'referenceTypeReceiver' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); + RoslynDebug.Assert(type is object, "Field 'type' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); + + this.ValueTypeReceiver = valueTypeReceiver; + this.ReferenceTypeReceiver = referenceTypeReceiver; + } + + public new TypeSymbol Type => base.Type!; + public BoundExpression ValueTypeReceiver { get; } + public BoundExpression ReferenceTypeReceiver { get; } + + [DebuggerStepThrough] + public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitComplexReceiver(this); + + public BoundComplexReceiver Update(BoundExpression valueTypeReceiver, BoundExpression referenceTypeReceiver, TypeSymbol type) + { + if (valueTypeReceiver != this.ValueTypeReceiver || referenceTypeReceiver != this.ReferenceTypeReceiver || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything)) + { + var result = new BoundComplexReceiver(this.Syntax, valueTypeReceiver, referenceTypeReceiver, type, this.HasErrors); + result.CopyAttributes(this); + return result; + } + return this; + } + } + internal sealed partial class BoundMethodGroup : BoundMethodOrPropertyGroup { public BoundMethodGroup(SyntaxNode syntax, ImmutableArray typeArgumentsOpt, string name, ImmutableArray methods, Symbol? lookupSymbolOpt, DiagnosticInfo? lookupError, BoundMethodGroupFlags? flags, FunctionTypeSymbol? functionType, BoundExpression? receiverOpt, LookupResultKind resultKind, bool hasErrors = false) @@ -6100,7 +6126,7 @@ public BoundObjectCreationExpression(SyntaxNode syntax, MethodSymbol constructor public override bool Expanded { get; } public override ImmutableArray ArgsToParamsOpt { get; } public override BitVector DefaultArguments { get; } - public ConstantValue? ConstantValueOpt { get; } + public override ConstantValue? ConstantValueOpt { get; } public override BoundObjectInitializerExpressionBase? InitializerExpressionOpt { get; } public override bool WasTargetTyped { get; } @@ -6848,7 +6874,7 @@ public BoundFieldAccess(SyntaxNode syntax, BoundExpression? receiverOpt, FieldSy public new TypeSymbol Type => base.Type!; public BoundExpression? ReceiverOpt { get; } public FieldSymbol FieldSymbol { get; } - public ConstantValue? ConstantValueOpt { get; } + public override ConstantValue? ConstantValueOpt { get; } public override LookupResultKind ResultKind { get; } public bool IsByValue { get; } public bool IsDeclaration { get; } @@ -7281,7 +7307,7 @@ public BoundNameOfOperator(SyntaxNode syntax, BoundExpression argument, Constant public new TypeSymbol Type => base.Type!; public BoundExpression Argument { get; } - public ConstantValue ConstantValueOpt { get; } + public override ConstantValue ConstantValueOpt { get; } [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitNameOfOperator(this); @@ -7311,7 +7337,7 @@ protected BoundInterpolatedStringBase(BoundKind kind, SyntaxNode syntax, Immutab } public ImmutableArray Parts { get; } - public ConstantValue? ConstantValueOpt { get; } + public override ConstantValue? ConstantValueOpt { get; } } internal sealed partial class BoundUnconvertedInterpolatedString : BoundInterpolatedStringBase @@ -7398,38 +7424,35 @@ public BoundInterpolatedStringHandlerPlaceholder Update(TypeSymbol? type) internal sealed partial class BoundInterpolatedStringArgumentPlaceholder : BoundValuePlaceholderBase { - public BoundInterpolatedStringArgumentPlaceholder(SyntaxNode syntax, int argumentIndex, uint valSafeToEscape, TypeSymbol type, bool hasErrors) + public BoundInterpolatedStringArgumentPlaceholder(SyntaxNode syntax, int argumentIndex, TypeSymbol type, bool hasErrors) : base(BoundKind.InterpolatedStringArgumentPlaceholder, syntax, type, hasErrors) { RoslynDebug.Assert(type is object, "Field 'type' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); this.ArgumentIndex = argumentIndex; - this.ValSafeToEscape = valSafeToEscape; } - public BoundInterpolatedStringArgumentPlaceholder(SyntaxNode syntax, int argumentIndex, uint valSafeToEscape, TypeSymbol type) + public BoundInterpolatedStringArgumentPlaceholder(SyntaxNode syntax, int argumentIndex, TypeSymbol type) : base(BoundKind.InterpolatedStringArgumentPlaceholder, syntax, type) { RoslynDebug.Assert(type is object, "Field 'type' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); this.ArgumentIndex = argumentIndex; - this.ValSafeToEscape = valSafeToEscape; } public new TypeSymbol Type => base.Type!; public int ArgumentIndex { get; } - public uint ValSafeToEscape { get; } [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitInterpolatedStringArgumentPlaceholder(this); - public BoundInterpolatedStringArgumentPlaceholder Update(int argumentIndex, uint valSafeToEscape, TypeSymbol type) + public BoundInterpolatedStringArgumentPlaceholder Update(int argumentIndex, TypeSymbol type) { - if (argumentIndex != this.ArgumentIndex || valSafeToEscape != this.ValSafeToEscape || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything)) + if (argumentIndex != this.ArgumentIndex || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything)) { - var result = new BoundInterpolatedStringArgumentPlaceholder(this.Syntax, argumentIndex, valSafeToEscape, type, this.HasErrors); + var result = new BoundInterpolatedStringArgumentPlaceholder(this.Syntax, argumentIndex, type, this.HasErrors); result.CopyAttributes(this); return result; } @@ -8054,29 +8077,26 @@ public BoundRelationalPattern Update(BinaryOperatorKind relation, BoundExpressio internal sealed partial class BoundDiscardExpression : BoundExpression { - public BoundDiscardExpression(SyntaxNode syntax, uint valEscape, TypeSymbol? type, bool hasErrors) + public BoundDiscardExpression(SyntaxNode syntax, TypeSymbol? type, bool hasErrors) : base(BoundKind.DiscardExpression, syntax, type, hasErrors) { - this.ValEscape = valEscape; } - public BoundDiscardExpression(SyntaxNode syntax, uint valEscape, TypeSymbol? type) + public BoundDiscardExpression(SyntaxNode syntax, TypeSymbol? type) : base(BoundKind.DiscardExpression, syntax, type) { - this.ValEscape = valEscape; } public new TypeSymbol? Type => base.Type; - public uint ValEscape { get; } [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitDiscardExpression(this); - public BoundDiscardExpression Update(uint valEscape, TypeSymbol? type) + public BoundDiscardExpression Update(TypeSymbol? type) { - if (valEscape != this.ValEscape || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything)) + if (!TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything)) { - var result = new BoundDiscardExpression(this.Syntax, valEscape, type, this.HasErrors); + var result = new BoundDiscardExpression(this.Syntax, type, this.HasErrors); result.CopyAttributes(this); return result; } @@ -8183,32 +8203,32 @@ public DeconstructionVariablePendingInference Update(Symbol variableSymbol, Boun internal sealed partial class OutDeconstructVarPendingInference : BoundExpression { - public OutDeconstructVarPendingInference(SyntaxNode syntax, Symbol? variableSymbol, uint valEscape, bool hasErrors) + public OutDeconstructVarPendingInference(SyntaxNode syntax, Symbol? variableSymbol, bool isDiscardExpression, bool hasErrors) : base(BoundKind.OutDeconstructVarPendingInference, syntax, null, hasErrors) { this.VariableSymbol = variableSymbol; - this.ValEscape = valEscape; + this.IsDiscardExpression = isDiscardExpression; } - public OutDeconstructVarPendingInference(SyntaxNode syntax, Symbol? variableSymbol, uint valEscape) + public OutDeconstructVarPendingInference(SyntaxNode syntax, Symbol? variableSymbol, bool isDiscardExpression) : base(BoundKind.OutDeconstructVarPendingInference, syntax, null) { this.VariableSymbol = variableSymbol; - this.ValEscape = valEscape; + this.IsDiscardExpression = isDiscardExpression; } public new TypeSymbol? Type => base.Type; public Symbol? VariableSymbol { get; } - public uint ValEscape { get; } + public bool IsDiscardExpression { get; } [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitOutDeconstructVarPendingInference(this); - public OutDeconstructVarPendingInference Update(Symbol? variableSymbol, uint valEscape) + public OutDeconstructVarPendingInference Update(Symbol? variableSymbol, bool isDiscardExpression) { - if (!Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(variableSymbol, this.VariableSymbol) || valEscape != this.ValEscape) + if (!Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(variableSymbol, this.VariableSymbol) || isDiscardExpression != this.IsDiscardExpression) { - var result = new OutDeconstructVarPendingInference(this.Syntax, variableSymbol, valEscape, this.HasErrors); + var result = new OutDeconstructVarPendingInference(this.Syntax, variableSymbol, isDiscardExpression, this.HasErrors); result.CopyAttributes(this); return result; } @@ -8662,6 +8682,8 @@ internal R VisitInternal(BoundNode node, A arg) return VisitConditionalReceiver((BoundConditionalReceiver)node, arg); case BoundKind.ComplexConditionalReceiver: return VisitComplexConditionalReceiver((BoundComplexConditionalReceiver)node, arg); + case BoundKind.ComplexReceiver: + return VisitComplexReceiver((BoundComplexReceiver)node, arg); case BoundKind.MethodGroup: return VisitMethodGroup((BoundMethodGroup)node, arg); case BoundKind.PropertyGroup: @@ -8957,6 +8979,7 @@ internal abstract partial class BoundTreeVisitor public virtual R VisitLoweredConditionalAccess(BoundLoweredConditionalAccess node, A arg) => this.DefaultVisit(node, arg); public virtual R VisitConditionalReceiver(BoundConditionalReceiver node, A arg) => this.DefaultVisit(node, arg); public virtual R VisitComplexConditionalReceiver(BoundComplexConditionalReceiver node, A arg) => this.DefaultVisit(node, arg); + public virtual R VisitComplexReceiver(BoundComplexReceiver node, A arg) => this.DefaultVisit(node, arg); public virtual R VisitMethodGroup(BoundMethodGroup node, A arg) => this.DefaultVisit(node, arg); public virtual R VisitPropertyGroup(BoundPropertyGroup node, A arg) => this.DefaultVisit(node, arg); public virtual R VisitCall(BoundCall node, A arg) => this.DefaultVisit(node, arg); @@ -9181,6 +9204,7 @@ internal abstract partial class BoundTreeVisitor public virtual BoundNode? VisitLoweredConditionalAccess(BoundLoweredConditionalAccess node) => this.DefaultVisit(node); public virtual BoundNode? VisitConditionalReceiver(BoundConditionalReceiver node) => this.DefaultVisit(node); public virtual BoundNode? VisitComplexConditionalReceiver(BoundComplexConditionalReceiver node) => this.DefaultVisit(node); + public virtual BoundNode? VisitComplexReceiver(BoundComplexReceiver node) => this.DefaultVisit(node); public virtual BoundNode? VisitMethodGroup(BoundMethodGroup node) => this.DefaultVisit(node); public virtual BoundNode? VisitPropertyGroup(BoundPropertyGroup node) => this.DefaultVisit(node); public virtual BoundNode? VisitCall(BoundCall node) => this.DefaultVisit(node); @@ -9907,6 +9931,12 @@ internal abstract partial class BoundTreeWalker : BoundTreeVisitor this.Visit(node.ReferenceTypeReceiver); return null; } + public override BoundNode? VisitComplexReceiver(BoundComplexReceiver node) + { + this.Visit(node.ValueTypeReceiver); + this.Visit(node.ReferenceTypeReceiver); + return null; + } public override BoundNode? VisitMethodGroup(BoundMethodGroup node) { this.Visit(node.ReceiverOpt); @@ -10270,7 +10300,7 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor public override BoundNode? VisitDeconstructValuePlaceholder(BoundDeconstructValuePlaceholder node) { TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.VariableSymbol, node.ValEscape, type); + return node.Update(node.VariableSymbol, node.IsDiscardExpression, type); } public override BoundNode? VisitTupleOperandPlaceholder(BoundTupleOperandPlaceholder node) { @@ -10280,7 +10310,7 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor public override BoundNode? VisitAwaitableValuePlaceholder(BoundAwaitableValuePlaceholder node) { TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.ValEscape, type); + return node.Update(type); } public override BoundNode? VisitDisposableValuePlaceholder(BoundDisposableValuePlaceholder node) { @@ -10300,12 +10330,12 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor public override BoundNode? VisitImplicitIndexerReceiverPlaceholder(BoundImplicitIndexerReceiverPlaceholder node) { TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.ValEscape, node.IsEquivalentToThisReference, type); + return node.Update(node.IsEquivalentToThisReference, type); } public override BoundNode? VisitListPatternReceiverPlaceholder(BoundListPatternReceiverPlaceholder node) { TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.ValEscape, type); + return node.Update(type); } public override BoundNode? VisitListPatternIndexPlaceholder(BoundListPatternIndexPlaceholder node) { @@ -10315,7 +10345,7 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor public override BoundNode? VisitSlicePatternReceiverPlaceholder(BoundSlicePatternReceiverPlaceholder node) { TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.ValEscape, type); + return node.Update(type); } public override BoundNode? VisitSlicePatternRangePlaceholder(BoundSlicePatternRangePlaceholder node) { @@ -10686,7 +10716,7 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor public override BoundNode? VisitBlock(BoundBlock node) { ImmutableArray statements = this.VisitList(node.Statements); - return node.Update(node.Locals, node.LocalFunctions, statements); + return node.Update(node.Locals, node.LocalFunctions, node.HasUnsafeModifier, statements); } public override BoundNode? VisitScope(BoundScope node) { @@ -11110,7 +11140,7 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor BoundExpression whenNotNull = (BoundExpression)this.Visit(node.WhenNotNull); BoundExpression? whenNullOpt = (BoundExpression?)this.Visit(node.WhenNullOpt); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(receiver, node.HasValueMethodOpt, whenNotNull, whenNullOpt, node.Id, type); + return node.Update(receiver, node.HasValueMethodOpt, whenNotNull, whenNullOpt, node.Id, node.ForceCopyOfNullableValueType, type); } public override BoundNode? VisitConditionalReceiver(BoundConditionalReceiver node) { @@ -11124,6 +11154,13 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor TypeSymbol? type = this.VisitType(node.Type); return node.Update(valueTypeReceiver, referenceTypeReceiver, type); } + public override BoundNode? VisitComplexReceiver(BoundComplexReceiver node) + { + BoundExpression valueTypeReceiver = (BoundExpression)this.Visit(node.ValueTypeReceiver); + BoundExpression referenceTypeReceiver = (BoundExpression)this.Visit(node.ReferenceTypeReceiver); + TypeSymbol? type = this.VisitType(node.Type); + return node.Update(valueTypeReceiver, referenceTypeReceiver, type); + } public override BoundNode? VisitMethodGroup(BoundMethodGroup node) { BoundExpression? receiverOpt = (BoundExpression?)this.Visit(node.ReceiverOpt); @@ -11395,7 +11432,7 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor public override BoundNode? VisitInterpolatedStringArgumentPlaceholder(BoundInterpolatedStringArgumentPlaceholder node) { TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.ArgumentIndex, node.ValSafeToEscape, type); + return node.Update(node.ArgumentIndex, type); } public override BoundNode? VisitStringInsert(BoundStringInsert node) { @@ -11522,7 +11559,7 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor public override BoundNode? VisitDiscardExpression(BoundDiscardExpression node) { TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.ValEscape, type); + return node.Update(type); } public override BoundNode? VisitThrowExpression(BoundThrowExpression node) { @@ -11545,7 +11582,7 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor public override BoundNode? VisitOutDeconstructVarPendingInference(OutDeconstructVarPendingInference node) { TypeSymbol? type = this.VisitType(node.Type); - return node.Update(node.VariableSymbol, node.ValEscape); + return node.Update(node.VariableSymbol, node.IsDiscardExpression); } public override BoundNode? VisitNonConstructorMethodBody(BoundNonConstructorMethodBody node) { @@ -11648,12 +11685,12 @@ public NullabilityRewriter(ImmutableDictionary locals = GetUpdatedArray(node, node.Locals); ImmutableArray localFunctions = GetUpdatedArray(node, node.LocalFunctions); ImmutableArray statements = this.VisitList(node.Statements); - return node.Update(locals, localFunctions, statements); + return node.Update(locals, localFunctions, node.HasUnsafeModifier, statements); } public override BoundNode? VisitScope(BoundScope node) @@ -13120,12 +13157,12 @@ public NullabilityRewriter(ImmutableDictionary methods = GetUpdatedArray(node, node.Methods); @@ -13867,7 +13922,7 @@ public NullabilityRewriter(ImmutableDictionary new TreeDumperNode("deconstructValuePlaceholder", null, new TreeDumperNode[] { new TreeDumperNode("variableSymbol", node.VariableSymbol, null), - new TreeDumperNode("valEscape", node.ValEscape, null), + new TreeDumperNode("isDiscardExpression", node.IsDiscardExpression, null), new TreeDumperNode("type", node.Type, null), new TreeDumperNode("isSuppressed", node.IsSuppressed, null), new TreeDumperNode("hasErrors", node.HasErrors, null) @@ -14228,7 +14283,6 @@ private BoundTreeDumperNodeProducer() ); public override TreeDumperNode VisitAwaitableValuePlaceholder(BoundAwaitableValuePlaceholder node, object? arg) => new TreeDumperNode("awaitableValuePlaceholder", null, new TreeDumperNode[] { - new TreeDumperNode("valEscape", node.ValEscape, null), new TreeDumperNode("type", node.Type, null), new TreeDumperNode("isSuppressed", node.IsSuppressed, null), new TreeDumperNode("hasErrors", node.HasErrors, null) @@ -14258,7 +14312,6 @@ private BoundTreeDumperNodeProducer() ); public override TreeDumperNode VisitImplicitIndexerReceiverPlaceholder(BoundImplicitIndexerReceiverPlaceholder node, object? arg) => new TreeDumperNode("implicitIndexerReceiverPlaceholder", null, new TreeDumperNode[] { - new TreeDumperNode("valEscape", node.ValEscape, null), new TreeDumperNode("isEquivalentToThisReference", node.IsEquivalentToThisReference, null), new TreeDumperNode("type", node.Type, null), new TreeDumperNode("isSuppressed", node.IsSuppressed, null), @@ -14267,7 +14320,6 @@ private BoundTreeDumperNodeProducer() ); public override TreeDumperNode VisitListPatternReceiverPlaceholder(BoundListPatternReceiverPlaceholder node, object? arg) => new TreeDumperNode("listPatternReceiverPlaceholder", null, new TreeDumperNode[] { - new TreeDumperNode("valEscape", node.ValEscape, null), new TreeDumperNode("type", node.Type, null), new TreeDumperNode("isSuppressed", node.IsSuppressed, null), new TreeDumperNode("hasErrors", node.HasErrors, null) @@ -14282,7 +14334,6 @@ private BoundTreeDumperNodeProducer() ); public override TreeDumperNode VisitSlicePatternReceiverPlaceholder(BoundSlicePatternReceiverPlaceholder node, object? arg) => new TreeDumperNode("slicePatternReceiverPlaceholder", null, new TreeDumperNode[] { - new TreeDumperNode("valEscape", node.ValEscape, null), new TreeDumperNode("type", node.Type, null), new TreeDumperNode("isSuppressed", node.IsSuppressed, null), new TreeDumperNode("hasErrors", node.HasErrors, null) @@ -14858,6 +14909,7 @@ private BoundTreeDumperNodeProducer() { new TreeDumperNode("locals", node.Locals, null), new TreeDumperNode("localFunctions", node.LocalFunctions, null), + new TreeDumperNode("hasUnsafeModifier", node.HasUnsafeModifier, null), new TreeDumperNode("statements", null, from x in node.Statements select Visit(x, null)), new TreeDumperNode("hasErrors", node.HasErrors, null) } @@ -15479,6 +15531,7 @@ private BoundTreeDumperNodeProducer() new TreeDumperNode("whenNotNull", null, new TreeDumperNode[] { Visit(node.WhenNotNull, null) }), new TreeDumperNode("whenNullOpt", null, new TreeDumperNode[] { Visit(node.WhenNullOpt, null) }), new TreeDumperNode("id", node.Id, null), + new TreeDumperNode("forceCopyOfNullableValueType", node.ForceCopyOfNullableValueType, null), new TreeDumperNode("type", node.Type, null), new TreeDumperNode("isSuppressed", node.IsSuppressed, null), new TreeDumperNode("hasErrors", node.HasErrors, null) @@ -15501,6 +15554,15 @@ private BoundTreeDumperNodeProducer() new TreeDumperNode("hasErrors", node.HasErrors, null) } ); + public override TreeDumperNode VisitComplexReceiver(BoundComplexReceiver node, object? arg) => new TreeDumperNode("complexReceiver", null, new TreeDumperNode[] + { + new TreeDumperNode("valueTypeReceiver", null, new TreeDumperNode[] { Visit(node.ValueTypeReceiver, null) }), + new TreeDumperNode("referenceTypeReceiver", null, new TreeDumperNode[] { Visit(node.ReferenceTypeReceiver, null) }), + new TreeDumperNode("type", node.Type, null), + new TreeDumperNode("isSuppressed", node.IsSuppressed, null), + new TreeDumperNode("hasErrors", node.HasErrors, null) + } + ); public override TreeDumperNode VisitMethodGroup(BoundMethodGroup node, object? arg) => new TreeDumperNode("methodGroup", null, new TreeDumperNode[] { new TreeDumperNode("typeArgumentsOpt", node.TypeArgumentsOpt, null), @@ -15962,7 +16024,6 @@ private BoundTreeDumperNodeProducer() public override TreeDumperNode VisitInterpolatedStringArgumentPlaceholder(BoundInterpolatedStringArgumentPlaceholder node, object? arg) => new TreeDumperNode("interpolatedStringArgumentPlaceholder", null, new TreeDumperNode[] { new TreeDumperNode("argumentIndex", node.ArgumentIndex, null), - new TreeDumperNode("valSafeToEscape", node.ValSafeToEscape, null), new TreeDumperNode("type", node.Type, null), new TreeDumperNode("isSuppressed", node.IsSuppressed, null), new TreeDumperNode("hasErrors", node.HasErrors, null) @@ -16131,7 +16192,6 @@ private BoundTreeDumperNodeProducer() ); public override TreeDumperNode VisitDiscardExpression(BoundDiscardExpression node, object? arg) => new TreeDumperNode("discardExpression", null, new TreeDumperNode[] { - new TreeDumperNode("valEscape", node.ValEscape, null), new TreeDumperNode("type", node.Type, null), new TreeDumperNode("isSuppressed", node.IsSuppressed, null), new TreeDumperNode("hasErrors", node.HasErrors, null) @@ -16166,7 +16226,7 @@ private BoundTreeDumperNodeProducer() public override TreeDumperNode VisitOutDeconstructVarPendingInference(OutDeconstructVarPendingInference node, object? arg) => new TreeDumperNode("outDeconstructVarPendingInference", null, new TreeDumperNode[] { new TreeDumperNode("variableSymbol", node.VariableSymbol, null), - new TreeDumperNode("valEscape", node.ValEscape, null), + new TreeDumperNode("isDiscardExpression", node.IsDiscardExpression, null), new TreeDumperNode("type", node.Type, null), new TreeDumperNode("isSuppressed", node.IsSuppressed, null), new TreeDumperNode("hasErrors", node.HasErrors, null) diff --git a/src/Compilers/CSharp/Portable/Lowering/ClosureConversion/ClosureConversion.cs b/src/Compilers/CSharp/Portable/Lowering/ClosureConversion/ClosureConversion.cs index b4f591c07eb0c..60e5904d86ae1 100644 --- a/src/Compilers/CSharp/Portable/Lowering/ClosureConversion/ClosureConversion.cs +++ b/src/Compilers/CSharp/Portable/Lowering/ClosureConversion/ClosureConversion.cs @@ -1146,7 +1146,7 @@ private BoundBlock RewriteBlock(BoundBlock node, ArrayBuilder p } // TODO: we may not need to update if there was nothing to rewrite. - return node.Update(newLocals.ToImmutableAndFree(), node.LocalFunctions, newStatements.ToImmutableAndFree()); + return node.Update(newLocals.ToImmutableAndFree(), node.LocalFunctions, node.HasUnsafeModifier, newStatements.ToImmutableAndFree()); } public override BoundNode VisitScope(BoundScope node) diff --git a/src/Compilers/CSharp/Portable/Lowering/ClosureConversion/ExpressionLambdaRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/ClosureConversion/ExpressionLambdaRewriter.cs index 674ea81b46203..aea66806e9933 100644 --- a/src/Compilers/CSharp/Portable/Lowering/ClosureConversion/ExpressionLambdaRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/ClosureConversion/ExpressionLambdaRewriter.cs @@ -485,7 +485,7 @@ private BoundExpression VisitAndPromoteEnumOperand(BoundExpression operand, Type if (literal != null) { // for compat reasons enum literals are directly promoted into underlying values - return Constant(literal.Update(literal.ConstantValue, promotedType)); + return Constant(literal.Update(literal.ConstantValueOpt, promotedType)); } else { @@ -737,7 +737,7 @@ private BoundExpression VisitFieldAccess(BoundFieldAccess node) private BoundExpression VisitIsOperator(BoundIsOperator node) { var operand = node.Operand; - if ((object)operand.Type == null && operand.ConstantValue != null && operand.ConstantValue.IsNull) + if ((object)operand.Type == null && operand.ConstantValueOpt != null && operand.ConstantValueOpt.IsNull) { operand = _bound.Null(_objectType); } @@ -956,7 +956,7 @@ private BoundExpression VisitObjectCreationContinued(BoundExpression creation, B private BoundExpression VisitObjectCreationExpressionInternal(BoundObjectCreationExpression node) { - if (node.ConstantValue != null) + if (node.ConstantValueOpt != null) { // typically a decimal constant. return Constant(node); diff --git a/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_ExpressionTrees.cs b/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_ExpressionTrees.cs index 65a1026188260..4e12cc426d91b 100644 --- a/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_ExpressionTrees.cs +++ b/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_ExpressionTrees.cs @@ -129,7 +129,7 @@ public override BoundNode VisitRangeExpression(BoundRangeExpression node) public override BoundNode VisitSizeOfOperator(BoundSizeOfOperator node) { - if (_inExpressionLambda && node.ConstantValue == null) + if (_inExpressionLambda && node.ConstantValueOpt == null) { Error(ErrorCode.ERR_ExpressionTreeContainsPointerOp, node); } @@ -723,7 +723,7 @@ public override BoundNode VisitConversion(BoundConversion node) switch (node.ConversionKind) { case ConversionKind.MethodGroup: - CheckMethodGroup((BoundMethodGroup)node.Operand, node.Conversion.Method, parentIsConversion: true, node.Type); + CheckMethodGroup((BoundMethodGroup)node.Operand, node.Conversion.Method, node.IsExtensionMethod, parentIsConversion: true, node.Type); return node; @@ -784,7 +784,7 @@ public override BoundNode VisitDelegateCreationExpression(BoundDelegateCreationE } else { - CheckMethodGroup((BoundMethodGroup)node.Argument, node.MethodOpt, parentIsConversion: true, convertedToType: node.Type); + CheckMethodGroup((BoundMethodGroup)node.Argument, node.MethodOpt, node.IsExtensionMethod, parentIsConversion: true, convertedToType: node.Type); } return null; @@ -792,11 +792,11 @@ public override BoundNode VisitDelegateCreationExpression(BoundDelegateCreationE public override BoundNode VisitMethodGroup(BoundMethodGroup node) { - CheckMethodGroup(node, method: null, parentIsConversion: false, convertedToType: null); + CheckMethodGroup(node, method: null, isExtensionMethod: false, parentIsConversion: false, convertedToType: null); return null; } - private void CheckMethodGroup(BoundMethodGroup node, MethodSymbol method, bool parentIsConversion, TypeSymbol convertedToType) + private void CheckMethodGroup(BoundMethodGroup node, MethodSymbol method, bool isExtensionMethod, bool parentIsConversion, TypeSymbol convertedToType) { // Formerly reported ERR_MemGroupInExpressionTree when this occurred, but the expanded // ERR_LambdaInIsAs makes this impossible (since the node will always be wrapped in @@ -822,7 +822,7 @@ private void CheckMethodGroup(BoundMethodGroup node, MethodSymbol method, bool p CheckReceiverIfField(node.ReceiverOpt); CheckReferenceToMethodIfLocalFunction(node, method); - if (method is null || method.RequiresInstanceReceiver) + if (method is null || method.RequiresInstanceReceiver || isExtensionMethod) { Visit(node.ReceiverOpt); } diff --git a/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_Warnings.cs b/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_Warnings.cs index 874869cc8e916..670235ec96fb9 100644 --- a/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_Warnings.cs +++ b/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_Warnings.cs @@ -314,25 +314,25 @@ private void CheckRelationals(BoundBinaryOperator node) // is doing something like "if (0xFFFFFFFFU == 0)" -- these are likely to be machine- // generated code. - if (node.Left.ConstantValue != null && node.Right.ConstantValue == null && node.Right.Kind == BoundKind.Conversion) + if (node.Left.ConstantValueOpt != null && node.Right.ConstantValueOpt == null && node.Right.Kind == BoundKind.Conversion) { - CheckVacuousComparisons(node, node.Left.ConstantValue, node.Right); + CheckVacuousComparisons(node, node.Left.ConstantValueOpt, node.Right); } - if (node.Right.ConstantValue != null && node.Left.ConstantValue == null && node.Left.Kind == BoundKind.Conversion) + if (node.Right.ConstantValueOpt != null && node.Left.ConstantValueOpt == null && node.Left.Kind == BoundKind.Conversion) { - CheckVacuousComparisons(node, node.Right.ConstantValue, node.Left); + CheckVacuousComparisons(node, node.Right.ConstantValueOpt, node.Left); } if (node.OperatorKind == BinaryOperatorKind.ObjectEqual || node.OperatorKind == BinaryOperatorKind.ObjectNotEqual) { TypeSymbol t; - if (node.Left.Type.SpecialType == SpecialType.System_Object && !IsExplicitCast(node.Left) && !(node.Left.ConstantValue != null && node.Left.ConstantValue.IsNull) && ConvertedHasEqual(node.OperatorKind, node.Right, out t)) + if (node.Left.Type.SpecialType == SpecialType.System_Object && !IsExplicitCast(node.Left) && !(node.Left.ConstantValueOpt != null && node.Left.ConstantValueOpt.IsNull) && ConvertedHasEqual(node.OperatorKind, node.Right, out t)) { // Possible unintended reference comparison; to get a value comparison, cast the left hand side to type '{0}' _diagnostics.Add(ErrorCode.WRN_BadRefCompareLeft, node.Syntax.Location, t); } - else if (node.Right.Type.SpecialType == SpecialType.System_Object && !IsExplicitCast(node.Right) && !(node.Right.ConstantValue != null && node.Right.ConstantValue.IsNull) && ConvertedHasEqual(node.OperatorKind, node.Left, out t)) + else if (node.Right.Type.SpecialType == SpecialType.System_Object && !IsExplicitCast(node.Right) && !(node.Right.ConstantValueOpt != null && node.Right.ConstantValueOpt.IsNull) && ConvertedHasEqual(node.OperatorKind, node.Left, out t)) { // Possible unintended reference comparison; to get a value comparison, cast the right hand side to type '{0}' _diagnostics.Add(ErrorCode.WRN_BadRefCompareRight, node.Syntax.Location, t); @@ -525,7 +525,7 @@ private void CheckForBitwiseOrSignExtend(BoundExpression node, BinaryOperatorKin // when they are non-constants, or when one is a constant, that we would similarly warn // when both are constants. - if (node.ConstantValue != null) + if (node.ConstantValueOpt != null) { return; } @@ -583,7 +583,7 @@ private static ConstantValue GetConstantValueForBitwiseOrCheck(BoundExpression o } } - ConstantValue constVal = operand.ConstantValue; + ConstantValue constVal = operand.ConstantValueOpt; if (constVal == null || !constVal.IsIntegral) { diff --git a/src/Compilers/CSharp/Portable/Lowering/Extensions.cs b/src/Compilers/CSharp/Portable/Lowering/Extensions.cs index 2786a37882ca7..7eb2a82a71731 100644 --- a/src/Compilers/CSharp/Portable/Lowering/Extensions.cs +++ b/src/Compilers/CSharp/Portable/Lowering/Extensions.cs @@ -77,7 +77,7 @@ public static bool NullableNeverHasValue(this BoundExpression expr) { Debug.Assert(expr != null); - if ((object)expr.Type == null && expr.ConstantValue == ConstantValue.Null) + if ((object)expr.Type == null && expr.ConstantValueOpt == ConstantValue.Null) { return true; } diff --git a/src/Compilers/CSharp/Portable/Lowering/Instrumentation/DebugInfoInjector.cs b/src/Compilers/CSharp/Portable/Lowering/Instrumentation/DebugInfoInjector.cs index 8a8be3e52ade2..ed08422012974 100644 --- a/src/Compilers/CSharp/Portable/Lowering/Instrumentation/DebugInfoInjector.cs +++ b/src/Compilers/CSharp/Portable/Lowering/Instrumentation/DebugInfoInjector.cs @@ -75,7 +75,7 @@ public override BoundStatement InstrumentFieldOrPropertyInitializer(BoundStateme if (rewritten.Kind == BoundKind.Block) { var block = (BoundBlock)rewritten; - return block.Update(block.Locals, block.LocalFunctions, ImmutableArray.Create(InstrumentFieldOrPropertyInitializer(block.Statements.Single(), syntax))); + return block.Update(block.Locals, block.LocalFunctions, block.HasUnsafeModifier, ImmutableArray.Create(InstrumentFieldOrPropertyInitializer(block.Statements.Single(), syntax))); } return InstrumentFieldOrPropertyInitializer(rewritten, syntax); diff --git a/src/Compilers/CSharp/Portable/Lowering/Instrumentation/DebugInfoInjector_SequencePoints.cs b/src/Compilers/CSharp/Portable/Lowering/Instrumentation/DebugInfoInjector_SequencePoints.cs index e245949e89f83..222102ddf9c6e 100644 --- a/src/Compilers/CSharp/Portable/Lowering/Instrumentation/DebugInfoInjector_SequencePoints.cs +++ b/src/Compilers/CSharp/Portable/Lowering/Instrumentation/DebugInfoInjector_SequencePoints.cs @@ -206,7 +206,7 @@ private static BoundExpression AddConditionSequencePoint(BoundExpression conditi // Add hidden sequence point unless the condition is a constant expression. // Constant expression must stay a const to not invalidate results of control flow analysis. - var valueExpression = (condition.ConstantValue == null) ? + var valueExpression = (condition.ConstantValueOpt == null) ? new BoundSequencePointExpression(syntax: null, expression: factory.Local(local), type: condition.Type) : condition; diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.DecisionDagRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.DecisionDagRewriter.cs index 37b0373478525..372986d83f3bc 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.DecisionDagRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.DecisionDagRewriter.cs @@ -141,7 +141,7 @@ public bool MightAssignSomething(BoundExpression expr) public override BoundNode Visit(BoundNode node) { // A constant expression cannot mutate anything - if (node is BoundExpression { ConstantValue: { } }) + if (node is BoundExpression { ConstantValueOpt: { } }) return null; // Stop visiting once we determine something might get assigned @@ -959,7 +959,7 @@ private void LowerWhenClauses(ImmutableArray sortedNodes) if (node is BoundWhenDecisionDagNode whenNode) { var whenExpression = whenNode.WhenExpression; - if (whenExpression is not null && whenExpression.ConstantValue != ConstantValue.True) + if (whenExpression is not null && whenExpression.ConstantValueOpt != ConstantValue.True) { LabelSymbol labelToWhenExpression; if (whenExpressionMap.TryGetValue(whenExpression, out var whenExpressionInfo)) @@ -1111,7 +1111,7 @@ void lowerWhenClause(BoundWhenDecisionDagNode whenClause) var whenFalse = whenClause.WhenFalse; var trueLabel = GetDagNodeLabel(whenTrue); - if (whenClause.WhenExpression != null && whenClause.WhenExpression.ConstantValue != ConstantValue.True) + if (whenClause.WhenExpression != null && whenClause.WhenExpression.ConstantValueOpt != ConstantValue.True) { addConditionalGoto(whenClause.WhenExpression, whenClause.Syntax, trueLabel, sectionBuilder); diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.PatternLocalRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.PatternLocalRewriter.cs index 98a77175e8182..a04284c5948d3 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.PatternLocalRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.PatternLocalRewriter.cs @@ -513,7 +513,7 @@ protected BoundDecisionDag ShareTempsAndEvaluateInput( // We share input variables if there is no when clause (because a when clause might mutate them). bool anyWhenClause = decisionDag.TopologicallySortedNodes - .Any(static node => node is BoundWhenDecisionDagNode { WhenExpression: { ConstantValue: null } }); + .Any(static node => node is BoundWhenDecisionDagNode { WhenExpression: { ConstantValueOpt: null } }); var inputDagTemp = BoundDagTemp.ForOriginalInput(loweredInput); if ((loweredInput.Kind == BoundKind.Local || loweredInput.Kind == BoundKind.Parameter) diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.cs index f7b330a7b5105..c556d9c130050 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.cs @@ -197,7 +197,7 @@ private PEModuleBuilder? EmitModule private BoundExpression? VisitExpressionImpl(BoundExpression node) { - ConstantValue? constantValue = node.ConstantValue; + ConstantValue? constantValue = node.ConstantValueOpt; if (constantValue != null) { TypeSymbol? type = node.Type; @@ -617,7 +617,7 @@ public override BoundNode VisitTypeOrInstanceInitializers(BoundTypeOrInstanceIni var block = (BoundBlock)initializer; var statement = RewriteExpressionStatement((BoundExpressionStatement)block.Statements.Single(), suppressInstrumentation: true); Debug.Assert(statement is { }); - statements.Add(block.Update(block.Locals, block.LocalFunctions, ImmutableArray.Create(statement))); + statements.Add(block.Update(block.Locals, block.LocalFunctions, block.HasUnsafeModifier, ImmutableArray.Create(statement))); } else { @@ -882,7 +882,7 @@ private static bool ShouldOptimizeOutInitializer(BoundStatement initializer) // internal static bool CanBePassedByReference(BoundExpression expr) { - if (expr.ConstantValue != null) + if (expr.ConstantValueOpt != null) { return false; } diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_AsOperator.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_AsOperator.cs index 82ecace25b688..78748cd0a4ffc 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_AsOperator.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_AsOperator.cs @@ -48,7 +48,7 @@ private BoundExpression MakeAsOperator( { var conversion = BoundNode.GetConversion(operandConversion, operandPlaceholder); - ConstantValue constantValue = Binder.GetAsOperatorConstantResult(rewrittenOperand.Type, rewrittenType, conversion.Kind, rewrittenOperand.ConstantValue); + ConstantValue constantValue = Binder.GetAsOperatorConstantResult(rewrittenOperand.Type, rewrittenType, conversion.Kind, rewrittenOperand.ConstantValueOpt); if (constantValue != null) { @@ -60,7 +60,7 @@ private BoundExpression MakeAsOperator( Debug.Assert(constantValue.IsNull); BoundExpression result = rewrittenType.IsNullableType() ? new BoundDefaultExpression(syntax, rewrittenType) : MakeLiteral(syntax, constantValue, rewrittenType); - if (rewrittenOperand.ConstantValue != null) + if (rewrittenOperand.ConstantValueOpt != null) { // No need to preserve any side-effects from the operand. // We also can keep the "constant" notion of the result, which diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_BinaryOperator.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_BinaryOperator.cs index 924280540d486..55e82a0530129 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_BinaryOperator.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_BinaryOperator.cs @@ -130,7 +130,7 @@ public BoundExpression VisitBinaryOperator(BoundBinaryOperator node, BoundUnaryO var stack = ArrayBuilder.GetInstance(); - for (BoundBinaryOperator? current = node; current != null && current.ConstantValue == null; current = current.Left as BoundBinaryOperator) + for (BoundBinaryOperator? current = node; current != null && current.ConstantValueOpt == null; current = current.Left as BoundBinaryOperator) { // The regular visit mechanism will handle this. if (current.InterpolatedStringHandlerData is not null || current.OperatorKind is BinaryOperatorKind.Utf8Addition) @@ -275,9 +275,9 @@ private BoundExpression MakeBinaryOperator( return RewriteDelegateOperation(syntax, operatorKind, loweredLeft, loweredRight, type, SpecialMember.System_Delegate__op_Inequality); case BinaryOperatorKind.LogicalBoolAnd: - if (loweredRight.ConstantValue == ConstantValue.True) return loweredLeft; - if (loweredLeft.ConstantValue == ConstantValue.True) return loweredRight; - if (loweredLeft.ConstantValue == ConstantValue.False) return loweredLeft; + if (loweredRight.ConstantValueOpt == ConstantValue.True) return loweredLeft; + if (loweredLeft.ConstantValueOpt == ConstantValue.True) return loweredRight; + if (loweredLeft.ConstantValueOpt == ConstantValue.False) return loweredLeft; if (loweredRight.Kind == BoundKind.Local || loweredRight.Kind == BoundKind.Parameter) { @@ -287,9 +287,9 @@ private BoundExpression MakeBinaryOperator( goto default; case BinaryOperatorKind.LogicalBoolOr: - if (loweredRight.ConstantValue == ConstantValue.False) return loweredLeft; - if (loweredLeft.ConstantValue == ConstantValue.False) return loweredRight; - if (loweredLeft.ConstantValue == ConstantValue.True) return loweredLeft; + if (loweredRight.ConstantValueOpt == ConstantValue.False) return loweredLeft; + if (loweredLeft.ConstantValueOpt == ConstantValue.False) return loweredRight; + if (loweredLeft.ConstantValueOpt == ConstantValue.True) return loweredLeft; if (loweredRight.Kind == BoundKind.Local || loweredRight.Kind == BoundKind.Parameter) { @@ -299,8 +299,8 @@ private BoundExpression MakeBinaryOperator( goto default; case BinaryOperatorKind.BoolAnd: - if (loweredRight.ConstantValue == ConstantValue.True) return loweredLeft; - if (loweredLeft.ConstantValue == ConstantValue.True) return loweredRight; + if (loweredRight.ConstantValueOpt == ConstantValue.True) return loweredLeft; + if (loweredLeft.ConstantValueOpt == ConstantValue.True) return loweredRight; // Note that we are using IsDefaultValue instead of False. // That is just to catch cases like default(bool) or others resulting in @@ -320,48 +320,48 @@ private BoundExpression MakeBinaryOperator( goto default; case BinaryOperatorKind.BoolOr: - if (loweredRight.ConstantValue == ConstantValue.False) return loweredLeft; - if (loweredLeft.ConstantValue == ConstantValue.False) return loweredRight; + if (loweredRight.ConstantValueOpt == ConstantValue.False) return loweredLeft; + if (loweredLeft.ConstantValueOpt == ConstantValue.False) return loweredRight; goto default; case BinaryOperatorKind.BoolEqual: - if (loweredLeft.ConstantValue == ConstantValue.True) return loweredRight; - if (loweredRight.ConstantValue == ConstantValue.True) return loweredLeft; + if (loweredLeft.ConstantValueOpt == ConstantValue.True) return loweredRight; + if (loweredRight.ConstantValueOpt == ConstantValue.True) return loweredLeft; Debug.Assert(loweredLeft.Type is { }); Debug.Assert(loweredRight.Type is { }); - if (loweredLeft.ConstantValue == ConstantValue.False) + if (loweredLeft.ConstantValueOpt == ConstantValue.False) return MakeUnaryOperator(UnaryOperatorKind.BoolLogicalNegation, syntax, method: null, constrainedToTypeOpt: null, loweredRight, loweredRight.Type); - if (loweredRight.ConstantValue == ConstantValue.False) + if (loweredRight.ConstantValueOpt == ConstantValue.False) return MakeUnaryOperator(UnaryOperatorKind.BoolLogicalNegation, syntax, method: null, constrainedToTypeOpt: null, loweredLeft, loweredLeft.Type); goto default; case BinaryOperatorKind.BoolNotEqual: - if (loweredLeft.ConstantValue == ConstantValue.False) return loweredRight; - if (loweredRight.ConstantValue == ConstantValue.False) return loweredLeft; + if (loweredLeft.ConstantValueOpt == ConstantValue.False) return loweredRight; + if (loweredRight.ConstantValueOpt == ConstantValue.False) return loweredLeft; Debug.Assert(loweredLeft.Type is { }); Debug.Assert(loweredRight.Type is { }); - if (loweredLeft.ConstantValue == ConstantValue.True) + if (loweredLeft.ConstantValueOpt == ConstantValue.True) return MakeUnaryOperator(UnaryOperatorKind.BoolLogicalNegation, syntax, method: null, constrainedToTypeOpt: null, loweredRight, loweredRight.Type); - if (loweredRight.ConstantValue == ConstantValue.True) + if (loweredRight.ConstantValueOpt == ConstantValue.True) return MakeUnaryOperator(UnaryOperatorKind.BoolLogicalNegation, syntax, method: null, constrainedToTypeOpt: null, loweredLeft, loweredLeft.Type); goto default; case BinaryOperatorKind.BoolXor: - if (loweredLeft.ConstantValue == ConstantValue.False) return loweredRight; - if (loweredRight.ConstantValue == ConstantValue.False) return loweredLeft; + if (loweredLeft.ConstantValueOpt == ConstantValue.False) return loweredRight; + if (loweredRight.ConstantValueOpt == ConstantValue.False) return loweredLeft; Debug.Assert(loweredLeft.Type is { }); Debug.Assert(loweredRight.Type is { }); - if (loweredLeft.ConstantValue == ConstantValue.True) + if (loweredLeft.ConstantValueOpt == ConstantValue.True) return MakeUnaryOperator(UnaryOperatorKind.BoolLogicalNegation, syntax, method: null, constrainedToTypeOpt: null, loweredRight, loweredRight.Type); - if (loweredRight.ConstantValue == ConstantValue.True) + if (loweredRight.ConstantValueOpt == ConstantValue.True) return MakeUnaryOperator(UnaryOperatorKind.BoolLogicalNegation, syntax, method: null, constrainedToTypeOpt: null, loweredLeft, loweredLeft.Type); goto default; @@ -466,11 +466,11 @@ private BoundExpression MakeBinaryOperator( { return _factory.MakeSequence(loweredLeft, loweredRight); } - if (loweredLeft.ConstantValue?.UInt64Value == 1) + if (loweredLeft.ConstantValueOpt?.UInt64Value == 1) { return loweredRight; } - if (loweredRight.ConstantValue?.UInt64Value == 1) + if (loweredRight.ConstantValueOpt?.UInt64Value == 1) { return loweredLeft; } @@ -528,7 +528,7 @@ private BoundExpression MakeBinaryOperator( } return (oldNode != null) ? - oldNode.Update(operatorKind, oldNode.ConstantValue, oldNode.Method, oldNode.ConstrainedToType, oldNode.ResultKind, loweredLeft, loweredRight, type) : + oldNode.Update(operatorKind, oldNode.ConstantValueOpt, oldNode.Method, oldNode.ConstrainedToType, oldNode.ResultKind, loweredLeft, loweredRight, type) : new BoundBinaryOperator(syntax, operatorKind, constantValueOpt: null, methodOpt: null, constrainedToTypeOpt: null, LookupResultKind.Viable, loweredLeft, loweredRight, type); } @@ -574,6 +574,7 @@ private BoundExpression RewriteLiftedBinaryOperator(SyntaxNode syntax, BinaryOpe whenNotNull: result, whenNullOpt: whenNullOpt, id: conditionalLeft.Id, + forceCopyOfNullableValueType: conditionalLeft.ForceCopyOfNullableValueType, type: result.Type! ); } @@ -619,7 +620,7 @@ private BoundExpression MakeDynamicLogicalBinaryOperator( // VisitUnaryOperator ensures we are never called with parentUnaryOperator != null when we can't perform the optimization. Debug.Assert(applyParentUnaryOperator == null || applyParentUnaryOperator.OperatorKind == testOperator); - ConstantValue? constantLeft = loweredLeft.ConstantValue ?? UnboxConstant(loweredLeft); + ConstantValue? constantLeft = loweredLeft.ConstantValueOpt ?? UnboxConstant(loweredLeft); if (testOperator == UnaryOperatorKind.DynamicFalse && constantLeft == ConstantValue.False || testOperator == UnaryOperatorKind.DynamicTrue && constantLeft == ConstantValue.True) { @@ -712,7 +713,7 @@ private BoundExpression MakeDynamicLogicalBinaryOperator( var conversion = (BoundConversion)expression; if (conversion.ConversionKind == ConversionKind.Boxing) { - return conversion.Operand.ConstantValue; + return conversion.Operand.ConstantValueOpt; } } @@ -1304,7 +1305,7 @@ private BoundExpression MakeLiftedBinaryOperatorConsequence( // TODO: There are expressions other than constants that have no side effects // TODO: or elidable side effects. - if (sideEffect.ConstantValue != null) + if (sideEffect.ConstantValueOpt != null) { return new BoundDefaultExpression(syntax, type); } @@ -1523,7 +1524,7 @@ private BoundExpression CaptureExpressionInTempIfNeeded( // operation smaller; the rest is gravy. BoundExpression? nonNullRight = NullableAlwaysHasValue(right); - if (nonNullRight != null && nonNullRight.ConstantValue != null && left.Kind == BoundKind.Sequence) + if (nonNullRight != null && nonNullRight.ConstantValueOpt != null && left.Kind == BoundKind.Sequence) { BoundSequence seq = (BoundSequence)left; if (seq.Value.Kind == BoundKind.ConditionalOperator) @@ -1900,7 +1901,7 @@ private BoundExpression RewriteNullableNullEquality( var whenNull = kind == BinaryOperatorKind.NullableNullEqual ? MakeBooleanConstant(syntax, true) : null; - return conditionalAccess.Update(conditionalAccess.Receiver, conditionalAccess.HasValueMethodOpt, whenNotNull, whenNull, conditionalAccess.Id, whenNotNull.Type!); + return conditionalAccess.Update(conditionalAccess.Receiver, conditionalAccess.HasValueMethodOpt, whenNotNull, whenNull, conditionalAccess.Id, conditionalAccess.ForceCopyOfNullableValueType, whenNotNull.Type!); } BoundExpression call = MakeNullableHasValue(syntax, nullable); @@ -1913,9 +1914,9 @@ private BoundExpression RewriteNullableNullEquality( private BoundExpression RewriteStringEquality(BoundBinaryOperator? oldNode, SyntaxNode syntax, BinaryOperatorKind operatorKind, BoundExpression loweredLeft, BoundExpression loweredRight, TypeSymbol type, SpecialMember member) { - if (oldNode != null && (loweredLeft.ConstantValue == ConstantValue.Null || loweredRight.ConstantValue == ConstantValue.Null)) + if (oldNode != null && (loweredLeft.ConstantValueOpt == ConstantValue.Null || loweredRight.ConstantValueOpt == ConstantValue.Null)) { - return oldNode.Update(operatorKind, oldNode.ConstantValue, oldNode.Method, oldNode.ConstrainedToType, oldNode.ResultKind, loweredLeft, loweredRight, type); + return oldNode.Update(operatorKind, oldNode.ConstantValueOpt, oldNode.Method, oldNode.ConstrainedToType, oldNode.ResultKind, loweredLeft, loweredRight, type); } var method = UnsafeGetSpecialTypeMethod(syntax, member); @@ -2002,14 +2003,14 @@ exprType is null || TypeSymbol boolType = _compilation.GetSpecialType(SpecialType.System_Boolean); // Fold compile-time comparisons. - if (rewrittenExpr.ConstantValue != null) + if (rewrittenExpr.ConstantValueOpt != null) { switch (operatorKind) { case BinaryOperatorKind.Equal: - return MakeLiteral(syntax, ConstantValue.Create(rewrittenExpr.ConstantValue.IsNull, ConstantValueTypeDiscriminator.Boolean), boolType); + return MakeLiteral(syntax, ConstantValue.Create(rewrittenExpr.ConstantValueOpt.IsNull, ConstantValueTypeDiscriminator.Boolean), boolType); case BinaryOperatorKind.NotEqual: - return MakeLiteral(syntax, ConstantValue.Create(!rewrittenExpr.ConstantValue.IsNull, ConstantValueTypeDiscriminator.Boolean), boolType); + return MakeLiteral(syntax, ConstantValue.Create(!rewrittenExpr.ConstantValueOpt.IsNull, ConstantValueTypeDiscriminator.Boolean), boolType); } } @@ -2052,7 +2053,7 @@ private BoundExpression RewriteBuiltInShiftOperation( int rightMask) { SyntaxNode rightSyntax = loweredRight.Syntax; - ConstantValue? rightConstantValue = loweredRight.ConstantValue; + ConstantValue? rightConstantValue = loweredRight.ConstantValueOpt; Debug.Assert(loweredRight.Type is { }); TypeSymbol rightType = loweredRight.Type; Debug.Assert(rightType.SpecialType == SpecialType.System_Int32); @@ -2124,7 +2125,7 @@ private BoundExpression RewriteBuiltInNativeShiftOperation( TypeSymbol leftType = loweredLeft.Type; Debug.Assert(leftType.SpecialType is SpecialType.System_IntPtr or SpecialType.System_UIntPtr); - ConstantValue? rightConstantValue = loweredRight.ConstantValue; + ConstantValue? rightConstantValue = loweredRight.ConstantValueOpt; Debug.Assert(loweredRight.Type is { }); TypeSymbol rightType = loweredRight.Type; Debug.Assert(rightType.SpecialType == SpecialType.System_Int32); @@ -2224,7 +2225,7 @@ private BoundExpression MakeSizeOfMultiplication(BoundExpression numericOperand, Debug.Assert(sizeOfExpression.Type is { SpecialType: SpecialType.System_Int32 }); // Common case: adding or subtracting one (e.g. for ++) - if (numericOperand.ConstantValue?.UInt64Value == 1) + if (numericOperand.ConstantValueOpt?.UInt64Value == 1) { // We could convert this to a native int (as the unoptimized multiplication would be), // but that would be a no-op (int to native int), so don't bother. @@ -2235,7 +2236,7 @@ private BoundExpression MakeSizeOfMultiplication(BoundExpression numericOperand, var numericSpecialType = numericOperand.Type.SpecialType; // Optimization: the size is exactly one byte, then multiplication is unnecessary. - if (sizeOfExpression.ConstantValue?.Int32Value == 1) + if (sizeOfExpression.ConstantValueOpt?.Int32Value == 1) { // As in ExpressionBinder::bindPtrAddMul, we apply the following conversions: // int -> int (add allows int32 operands and will extend to native int if necessary) @@ -2256,7 +2257,7 @@ private BoundExpression MakeSizeOfMultiplication(BoundExpression numericOperand, // As a result, in checked contexts, we will force sign-extending cast to be sure if (isChecked) { - var constVal = numericOperand.ConstantValue; + var constVal = numericOperand.ConstantValueOpt; if (constVal == null || constVal.Int32Value < 0) { destinationType = SpecialType.System_IntPtr; @@ -2267,7 +2268,7 @@ private BoundExpression MakeSizeOfMultiplication(BoundExpression numericOperand, { // add operator treats operands as signed and will sign-extend on x64 // to prevent sign-extending, convert the operand to unsigned native int. - var constVal = numericOperand.ConstantValue; + var constVal = numericOperand.ConstantValueOpt; if (constVal == null || constVal.UInt32Value > int.MaxValue) { destinationType = SpecialType.System_UIntPtr; diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Block.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Block.cs index 44d4337973e06..a79417ba65866 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Block.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Block.cs @@ -2,13 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Immutable; -using System.Diagnostics; using Microsoft.CodeAnalysis.CSharp.Symbols; -using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.PooledObjects; -using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.CSharp { @@ -21,7 +17,7 @@ public override BoundNode VisitBlock(BoundBlock node) if (!this.Instrument || (node != _rootStatement && (node.WasCompilerGenerated || node.Syntax.Kind() != SyntaxKind.Block))) { - return node.Update(node.Locals, node.LocalFunctions, builder.ToImmutableAndFree()); + return node.Update(node.Locals, node.LocalFunctions, node.HasUnsafeModifier, builder.ToImmutableAndFree()); } LocalSymbol? synthesizedLocal; @@ -41,7 +37,7 @@ public override BoundNode VisitBlock(BoundBlock node) builder.Add(epilogue); } - return new BoundBlock(node.Syntax, synthesizedLocal == null ? node.Locals : node.Locals.Add(synthesizedLocal), node.LocalFunctions, builder.ToImmutableAndFree(), node.HasErrors); + return new BoundBlock(node.Syntax, synthesizedLocal == null ? node.Locals : node.Locals.Add(synthesizedLocal), node.LocalFunctions, node.HasUnsafeModifier, builder.ToImmutableAndFree(), node.HasErrors); } /// diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Call.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Call.cs index a6495a3957afc..0df64315a6b4e 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Call.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Call.cs @@ -302,7 +302,7 @@ private static bool IsSafeForReordering(BoundExpression expression, RefKind kind var current = expression; while (true) { - if (current.ConstantValue != null) + if (current.ConstantValueOpt != null) { return true; } @@ -694,29 +694,23 @@ private void ReferToTempIfReferenceTypeReceiver(BoundLocal receiverTemp, ref Bou temps.Add(intermediateRef.LocalSymbol); extraRefInitialization = assignmentToTemp.Update(intermediateRef, assignmentToTemp.Right, assignmentToTemp.IsRef, assignmentToTemp.Type); - // If condition `(object)default(T) != null` is true at execution time, - // the T is a value type. And it is a reference type otherwise. - var isValueTypeCheck = _factory.ObjectNotEqual( - _factory.Convert(_factory.SpecialType(SpecialType.System_Object), _factory.Default(receiverType)), - _factory.Null(_factory.SpecialType(SpecialType.System_Object))); - // `receiverTemp` initialization is adjusted as follows: // If we are dealing with a value type, use value of the intermediate ref. // Otherwise, use an address of a temp where we store the underlying reference type instance. assignmentToTemp = assignmentToTemp.Update( assignmentToTemp.Left, - _factory.Conditional( - isValueTypeCheck, - intermediateRef, - _factory.Sequence(new BoundExpression[] { _factory.AssignmentExpression(cache, intermediateRef) }, cache), - receiverType, - isRef: true), +#pragma warning disable format + new BoundComplexReceiver(receiverTemp.Syntax, + intermediateRef, + _factory.Sequence(new BoundExpression[] { _factory.AssignmentExpression(cache, intermediateRef) }, cache), + receiverType) { WasCompilerGenerated = true }, +#pragma warning restore format assignmentToTemp.IsRef, assignmentToTemp.Type); // SpillSequenceSpiller should be able to recognize this node in order to handle its spilling. - Debug.Assert(SpillSequenceSpiller.IsComplexConditionalInitializationOfReceiverRef(assignmentToTemp, out _, out _, out _, out _, out _)); + Debug.Assert(SpillSequenceSpiller.IsComplexConditionalInitializationOfReceiverRef(assignmentToTemp, out _, out _, out _, out _)); } else { diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CompoundAssignmentOperator.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CompoundAssignmentOperator.cs index d4734524a4a3c..ada9123735674 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CompoundAssignmentOperator.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CompoundAssignmentOperator.cs @@ -716,7 +716,7 @@ private BoundExpression TransformCompoundAssignmentLHS(BoundExpression originalL if (TransformCompoundAssignmentFieldOrEventAccessReceiver(eventAccess.EventSymbol, ref receiverOpt, stores, temps)) { - return MakeEventAccess(eventAccess.Syntax, receiverOpt, eventAccess.EventSymbol, eventAccess.ConstantValue, eventAccess.ResultKind, eventAccess.Type); + return MakeEventAccess(eventAccess.Syntax, receiverOpt, eventAccess.EventSymbol, eventAccess.ConstantValueOpt, eventAccess.ResultKind, eventAccess.Type); } } break; @@ -754,7 +754,7 @@ private BoundExpression BoxReceiver(BoundExpression rewrittenReceiver, NamedType Conversion.Boxing, memberContainingType, @checked: false, - constantValueOpt: rewrittenReceiver.ConstantValue); + constantValueOpt: rewrittenReceiver.ConstantValueOpt); } private BoundExpression SpillArrayElementAccess( @@ -812,7 +812,7 @@ internal static bool CanChangeValueBetweenReads( return false; } - if (expression.ConstantValue != null) + if (expression.ConstantValueOpt != null) { var type = expression.Type; return !ConstantValueIsTrivial(type); @@ -848,7 +848,7 @@ internal static bool CanChangeValueBetweenReads( internal static bool ReadIsSideeffecting( BoundExpression expression) { - if (expression.ConstantValue != null) + if (expression.ConstantValueOpt != null) { return false; } diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ConditionalAccess.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ConditionalAccess.cs index 59b8377e6317c..a392901ac2b37 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ConditionalAccess.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ConditionalAccess.cs @@ -157,6 +157,7 @@ private enum ConditionalAccessLoweringKind loweredAccessExpression, null, currentConditionalAccessID, + forceCopyOfNullableValueType: true, type); break; diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ConditionalOperator.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ConditionalOperator.cs index cea668ad910fb..250131f0be753 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ConditionalOperator.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ConditionalOperator.cs @@ -18,13 +18,13 @@ internal sealed partial class LocalRewriter public override BoundNode VisitConditionalOperator(BoundConditionalOperator node) { // just a fact, not a requirement (VisitExpression would have rewritten otherwise) - Debug.Assert(node.ConstantValue == null); + Debug.Assert(node.ConstantValueOpt == null); var rewrittenCondition = VisitExpression(node.Condition); var rewrittenConsequence = VisitExpression(node.Consequence); var rewrittenAlternative = VisitExpression(node.Alternative); - if (rewrittenCondition.ConstantValue == null) + if (rewrittenCondition.ConstantValueOpt == null) { return node.Update(node.IsRef, rewrittenCondition, rewrittenConsequence, rewrittenAlternative, node.ConstantValueOpt, node.NaturalTypeOpt, node.WasTargetTyped, node.Type); } @@ -48,7 +48,7 @@ private static BoundExpression RewriteConditionalOperator( TypeSymbol rewrittenType, bool isRef) { - ConstantValue? conditionConstantValue = rewrittenCondition.ConstantValue; + ConstantValue? conditionConstantValue = rewrittenCondition.ConstantValueOpt; if (conditionConstantValue == ConstantValue.True) { return rewrittenConsequence; diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Conversion.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Conversion.cs index f6cea4e52a51e..8c02aa6567068 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Conversion.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Conversion.cs @@ -66,7 +66,7 @@ public override BoundNode VisitConversion(BoundConversion node) var rewrittenOperand = VisitExpression(node.Operand); _inExpressionLambda = wasInExpressionLambda; - var result = MakeConversionNode(node, node.Syntax, rewrittenOperand, node.Conversion, node.Checked, node.ExplicitCastInCode, node.ConstantValue, rewrittenType); + var result = MakeConversionNode(node, node.Syntax, rewrittenOperand, node.Conversion, node.Checked, node.ExplicitCastInCode, node.ConstantValueOpt, rewrittenType); var toType = node.Type; Debug.Assert(result.Type!.Equals(toType, TypeCompareKind.IgnoreDynamicAndTupleNames | TypeCompareKind.IgnoreNullableModifiersForReferenceTypes)); @@ -208,7 +208,7 @@ private static bool IsFloatingPointExpressionOfUnknownPrecision(BoundExpression return false; } - if (rewrittenNode.ConstantValue != null) + if (rewrittenNode.ConstantValueOpt != null) { return false; } diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_DeconstructionAssignmentOperator.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_DeconstructionAssignmentOperator.cs index 32ebce8141368..9399528e0b919 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_DeconstructionAssignmentOperator.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_DeconstructionAssignmentOperator.cs @@ -68,7 +68,7 @@ internal sealed partial class LocalRewriter VisitExpression(conditional.Condition), RewriteDeconstruction(lhsTargets, conversion, leftType, conditional.Consequence, isUsed: true)!, RewriteDeconstruction(lhsTargets, conversion, leftType, conditional.Alternative, isUsed: true)!, - conditional.ConstantValue, + conditional.ConstantValueOpt, leftType, wasTargetTyped: true, leftType); diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Event.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Event.cs index 2651e16783e71..db02f764d57a9 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Event.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Event.cs @@ -204,7 +204,7 @@ public override BoundNode VisitEventAccess(BoundEventAccess node) Debug.Assert(node.IsUsableAsField); BoundExpression? rewrittenReceiver = VisitExpression(node.ReceiverOpt); - return MakeEventAccess(node.Syntax, rewrittenReceiver, node.EventSymbol, node.ConstantValue, node.ResultKind, node.Type); + return MakeEventAccess(node.Syntax, rewrittenReceiver, node.EventSymbol, node.ConstantValueOpt, node.ResultKind, node.Type); } private BoundExpression MakeEventAccess( diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Field.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Field.cs index 2cf86302db342..4f45015fa8ecb 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Field.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Field.cs @@ -11,7 +11,7 @@ internal sealed partial class LocalRewriter public override BoundNode VisitFieldAccess(BoundFieldAccess node) { BoundExpression? rewrittenReceiver = VisitExpression(node.ReceiverOpt); - return MakeFieldAccess(node.Syntax, rewrittenReceiver, node.FieldSymbol, node.ConstantValue, node.ResultKind, node.Type, node); + return MakeFieldAccess(node.Syntax, rewrittenReceiver, node.FieldSymbol, node.ConstantValueOpt, node.ResultKind, node.Type, node); } private BoundExpression MakeFieldAccess( diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_FixedStatement.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_FixedStatement.cs index f168a05abfce0..7fed69a66422c 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_FixedStatement.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_FixedStatement.cs @@ -380,6 +380,7 @@ private BoundStatement InitializeFixedStatementGetPinnable( whenNotNull: pinAndGetPtr, whenNullOpt: null, // just return default(T*) currentConditionalAccessID, + forceCopyOfNullableValueType: false, localType); } diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IndexerAccess.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IndexerAccess.cs index 9c105010a8a37..7b0bbef5edd47 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IndexerAccess.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IndexerAccess.cs @@ -302,7 +302,7 @@ private BoundExpression GetUnderlyingIndexerOrSliceAccess( BoundExpression lengthAccess = VisitExpression(node.LengthOrCountAccess); // ensure we evaluate the input before accessing length, unless it is an array length - if (makeOffsetInput.ConstantValue is null && lengthAccess.Kind is not BoundKind.ArrayLength) + if (makeOffsetInput.ConstantValueOpt is null && lengthAccess.Kind is not BoundKind.ArrayLength) { makeOffsetInput = F.StoreToTemp(makeOffsetInput, out BoundAssignmentOperator inputStore); locals.Add(((BoundLocal)makeOffsetInput).LocalSymbol); @@ -401,7 +401,7 @@ private BoundExpression MakePatternIndexOffsetExpression( Debug.Assert(lengthAccess is not null); Debug.Assert(loweredExpr.Type!.SpecialType == SpecialType.System_Int32); - if (loweredExpr.ConstantValue?.Int32Value == 0) + if (loweredExpr.ConstantValueOpt?.Int32Value == 0) { return lengthAccess; } @@ -471,8 +471,8 @@ private BoundExpression DetermineMakePatternIndexOffsetExpressionStrategy( } else if (unloweredExpr is BoundObjectCreationExpression { Constructor: MethodSymbol constructor, Arguments: { Length: 2 } arguments, ArgsToParamsOpt: { IsDefaultOrEmpty: true }, InitializerExpressionOpt: null } && (object)constructor == _compilation.GetWellKnownTypeMember(WellKnownMember.System_Index__ctor) && - arguments[0] is { Type.SpecialType: SpecialType.System_Int32, ConstantValue.Value: int _ and >= 0 } index && - arguments[1] is { Type.SpecialType: SpecialType.System_Boolean, ConstantValue.Value: bool fromEnd }) + arguments[0] is { Type.SpecialType: SpecialType.System_Int32, ConstantValueOpt.Value: int _ and >= 0 } index && + arguments[1] is { Type.SpecialType: SpecialType.System_Boolean, ConstantValueOpt.Value: bool fromEnd }) { if (fromEnd) { @@ -696,7 +696,7 @@ private BoundExpression VisitRangePatternIndexerAccess(BoundImplicitIndexerAcces if ((rewriteFlags & captureStartOffset) != 0) { Debug.Assert(startMakeOffsetInput is not null); - if (startMakeOffsetInput.ConstantValue is null) + if (startMakeOffsetInput.ConstantValueOpt is null) { startMakeOffsetInput = F.StoreToTemp(startMakeOffsetInput, out BoundAssignmentOperator inputStore); localsBuilder.Add(((BoundLocal)startMakeOffsetInput).LocalSymbol); @@ -707,7 +707,7 @@ private BoundExpression VisitRangePatternIndexerAccess(BoundImplicitIndexerAcces if ((rewriteFlags & captureEndOffset) != 0) { Debug.Assert(endMakeOffsetInput is not null); - if (endMakeOffsetInput.ConstantValue is null) + if (endMakeOffsetInput.ConstantValueOpt is null) { endMakeOffsetInput = F.StoreToTemp(endMakeOffsetInput, out BoundAssignmentOperator inputStore); localsBuilder.Add(((BoundLocal)endMakeOffsetInput).LocalSymbol); @@ -733,7 +733,7 @@ private BoundExpression VisitRangePatternIndexerAccess(BoundImplicitIndexerAcces startExpr = MakePatternIndexOffsetExpression(startMakeOffsetInput, lengthAccess, startStrategy); - if ((rewriteFlags & captureStartValue) != 0 && startExpr.ConstantValue is null) + if ((rewriteFlags & captureStartValue) != 0 && startExpr.ConstantValueOpt is null) { var startLocal = F.StoreToTemp(startExpr, out var startStore); localsBuilder.Add(startLocal.LocalSymbol); @@ -743,11 +743,11 @@ private BoundExpression VisitRangePatternIndexerAccess(BoundImplicitIndexerAcces BoundExpression endExpr = MakePatternIndexOffsetExpression(endMakeOffsetInput, lengthAccess, endStrategy); - if (startExpr.ConstantValue?.Int32Value == 0) + if (startExpr.ConstantValueOpt?.Int32Value == 0) { rangeSizeExpr = endExpr; } - else if (startExpr.ConstantValue is { Int32Value: var startConst } && endExpr.ConstantValue is { Int32Value: var endConst }) + else if (startExpr.ConstantValueOpt is { Int32Value: var startConst } && endExpr.ConstantValueOpt is { Int32Value: var endConst }) { rangeSizeExpr = F.Literal(unchecked(endConst - startConst)); } diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IsOperator.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IsOperator.cs index ab71540522885..64fb5b8983d7b 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IsOperator.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IsOperator.cs @@ -48,14 +48,14 @@ private BoundExpression MakeIsOperator( var operandType = rewrittenOperand.Type; var targetType = rewrittenTargetType.Type; - Debug.Assert(operandType is { } || rewrittenOperand.ConstantValue!.IsNull); + Debug.Assert(operandType is { } || rewrittenOperand.ConstantValueOpt!.IsNull); Debug.Assert(targetType is { }); // TODO: Handle dynamic operand type and target type if (!_inExpressionLambda) { - ConstantValue constantValue = Binder.GetIsOperatorConstantResult(operandType, targetType, conversionKind, rewrittenOperand.ConstantValue); + ConstantValue constantValue = Binder.GetIsOperatorConstantResult(operandType, targetType, conversionKind, rewrittenOperand.ConstantValueOpt); if (constantValue != null) { diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Literal.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Literal.cs index 8eaf248a631ce..6dbcf1733d0d6 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Literal.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Literal.cs @@ -16,8 +16,8 @@ internal partial class LocalRewriter { public override BoundNode VisitLiteral(BoundLiteral node) { - Debug.Assert(node.ConstantValue is { }); - return MakeLiteral(node.Syntax, node.ConstantValue, node.Type, oldNodeOpt: node); + Debug.Assert(node.ConstantValueOpt is { }); + return MakeLiteral(node.Syntax, node.ConstantValueOpt, node.Type, oldNodeOpt: node); } private BoundExpression MakeLiteral(SyntaxNode syntax, ConstantValue constantValue, TypeSymbol? type, BoundLiteral? oldNodeOpt = null) diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_LockStatement.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_LockStatement.cs index a172ef0e20c77..2fcc1f67eaf81 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_LockStatement.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_LockStatement.cs @@ -29,11 +29,11 @@ public override BoundNode VisitLockStatement(BoundLockStatement node) { // This isn't particularly elegant, but hopefully locking on null is // not very common. - Debug.Assert(rewrittenArgument.ConstantValue == ConstantValue.Null); + Debug.Assert(rewrittenArgument.ConstantValueOpt == ConstantValue.Null); argumentType = _compilation.GetSpecialType(SpecialType.System_Object); rewrittenArgument = MakeLiteral( rewrittenArgument.Syntax, - rewrittenArgument.ConstantValue, + rewrittenArgument.ConstantValueOpt, argumentType); //need to have a non-null type here for TempHelpers.StoreToTemp. } @@ -49,7 +49,7 @@ public override BoundNode VisitLockStatement(BoundLockStatement node) Conversion.Boxing, argumentType, @checked: false, - constantValueOpt: rewrittenArgument.ConstantValue); + constantValueOpt: rewrittenArgument.ConstantValueOpt); } BoundAssignmentOperator assignmentToLockTemp; diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_NullCoalescingOperator.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_NullCoalescingOperator.cs index a74f8f6763deb..2e2a3d49d965c 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_NullCoalescingOperator.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_NullCoalescingOperator.cs @@ -72,9 +72,9 @@ private BoundExpression MakeNullCoalescingOperator( return rewrittenRight; } - if (rewrittenLeft.ConstantValue != null) + if (rewrittenLeft.ConstantValueOpt != null) { - Debug.Assert(!rewrittenLeft.ConstantValue.IsNull); + Debug.Assert(!rewrittenLeft.ConstantValueOpt.IsNull); return GetConvertedLeftForNullCoalescingOperator(rewrittenLeft, leftPlaceholder, leftConversion, rewrittenResultType); } @@ -125,6 +125,7 @@ private BoundExpression MakeNullCoalescingOperator( whenNotNull: notNullAccess, whenNullOpt: whenNullOpt, id: conditionalAccess.Id, + forceCopyOfNullableValueType: conditionalAccess.ForceCopyOfNullableValueType, type: rewrittenResultType ); } @@ -166,7 +167,7 @@ private BoundExpression MakeNullCoalescingOperator( rewrittenType: rewrittenResultType, isRef: false); - Debug.Assert(conditionalExpression.ConstantValue == null); // we shouldn't have hit this else case otherwise + Debug.Assert(conditionalExpression.ConstantValueOpt == null); // we shouldn't have hit this else case otherwise Debug.Assert(conditionalExpression.Type!.Equals(rewrittenResultType, TypeCompareKind.IgnoreDynamicAndTupleNames | TypeCompareKind.IgnoreNullableModifiersForReferenceTypes)); return new BoundSequence( diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_PatternSwitchStatement.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_PatternSwitchStatement.cs index cd187029d23b0..368fdfd490826 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_PatternSwitchStatement.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_PatternSwitchStatement.cs @@ -79,7 +79,7 @@ private BoundStatement LowerSwitchStatement(BoundSwitchStatement node) // EnC: We need to insert a hidden sequence point to handle function remapping in case // the containing method is edited while methods invoked in the expression are being executed. var instrumentedExpression = _localRewriter._instrumenter.InstrumentSwitchStatementExpression(node, loweredSwitchGoverningExpression, _factory); - if (loweredSwitchGoverningExpression.ConstantValue == null) + if (loweredSwitchGoverningExpression.ConstantValueOpt == null) { loweredSwitchGoverningExpression = instrumentedExpression; } diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_StackAlloc.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_StackAlloc.cs index 9b668d51509bc..4ce952d314474 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_StackAlloc.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_StackAlloc.cs @@ -28,7 +28,7 @@ private BoundNode VisitStackAllocArrayCreationBase(BoundStackAllocArrayCreationB var type = stackAllocNode.Type; Debug.Assert(type is { }); - if (rewrittenCount.ConstantValue?.Int32Value == 0) + if (rewrittenCount.ConstantValueOpt?.Int32Value == 0) { // either default(span) or nullptr return _factory.Default(type); @@ -116,14 +116,14 @@ private BoundExpression RewriteStackAllocCountToSize(BoundExpression countExpres BoundExpression sizeOfExpression = _factory.Sizeof(elementType); - var sizeConst = sizeOfExpression.ConstantValue; + var sizeConst = sizeOfExpression.ConstantValueOpt; if (sizeConst != null) { int size = sizeConst.Int32Value; Debug.Assert(size > 0); // common case: stackalloc int[123] - var countConst = countExpression.ConstantValue; + var countConst = countExpression.ConstantValueOpt; if (countConst != null) { var count = countConst.Int32Value; diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_StringConcat.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_StringConcat.cs index 62c9f76aa09cc..5c69a2cbb0886 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_StringConcat.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_StringConcat.cs @@ -49,8 +49,8 @@ private BoundExpression RewriteStringConcatenation(SyntaxNode syntax, BinaryOper loweredLeft = ConvertConcatExprToString(syntax, loweredLeft); loweredRight = ConvertConcatExprToString(syntax, loweredRight); - Debug.Assert(loweredLeft.Type is { } && (loweredLeft.Type.IsStringType() || loweredLeft.Type.IsErrorType()) || loweredLeft.ConstantValue?.IsNull == true); - Debug.Assert(loweredRight.Type is { } && (loweredRight.Type.IsStringType() || loweredRight.Type.IsErrorType()) || loweredRight.ConstantValue?.IsNull == true); + Debug.Assert(loweredLeft.Type is { } && (loweredLeft.Type.IsStringType() || loweredLeft.Type.IsErrorType()) || loweredLeft.ConstantValueOpt?.IsNull == true); + Debug.Assert(loweredRight.Type is { } && (loweredRight.Type.IsStringType() || loweredRight.Type.IsErrorType()) || loweredRight.ConstantValueOpt?.IsNull == true); // try fold two args without flattening. var folded = TryFoldTwoConcatOperands(loweredLeft, loweredRight); @@ -195,7 +195,7 @@ private bool TryExtractStringConcatArgs(BoundExpression lowered, out ImmutableAr // To be safe, check that the constant value is actually a string before // attempting to access its value as a string. - var rightConstant = boundCoalesce.RightOperand.ConstantValue; + var rightConstant = boundCoalesce.RightOperand.ConstantValueOpt; if (rightConstant != null && rightConstant.IsString && rightConstant.StringValue.Length == 0) { arguments = ImmutableArray.Create(boundCoalesce.LeftOperand); @@ -216,8 +216,8 @@ private bool TryExtractStringConcatArgs(BoundExpression lowered, out ImmutableAr private BoundExpression? TryFoldTwoConcatOperands(BoundExpression loweredLeft, BoundExpression loweredRight) { // both left and right are constants - var leftConst = loweredLeft.ConstantValue; - var rightConst = loweredRight.ConstantValue; + var leftConst = loweredLeft.ConstantValueOpt; + var rightConst = loweredRight.ConstantValueOpt; if (leftConst != null && rightConst != null) { @@ -250,7 +250,7 @@ private bool TryExtractStringConcatArgs(BoundExpression lowered, out ImmutableAr private static bool IsNullOrEmptyStringConstant(BoundExpression operand) { - return (operand.ConstantValue != null && string.IsNullOrEmpty(operand.ConstantValue.StringValue)) || + return (operand.ConstantValueOpt != null && string.IsNullOrEmpty(operand.ConstantValueOpt.StringValue)) || operand.IsDefaultValue(); } @@ -385,7 +385,7 @@ private BoundExpression ConvertConcatExprToString(SyntaxNode syntax, BoundExpres // simply make it a literal string instead and avoid any // allocations for converting the char to a string at run time. // Similarly if it's a literal null, don't do anything special. - if (expr is { ConstantValue: { } cv }) + if (expr is { ConstantValueOpt: { } cv }) { if (cv.SpecialType == SpecialType.System_Char) { @@ -445,7 +445,7 @@ private BoundExpression ConvertConcatExprToString(SyntaxNode syntax, BoundExpres // This is to mimic the old behaviour, where value types would be boxed before ToString was called on them, // but with optimizations for readonly methods. bool callWithoutCopy = expr.Type.IsReferenceType || - expr.ConstantValue != null || + expr.ConstantValueOpt != null || (structToStringMethod == null && !expr.Type.IsTypeParameter()) || structToStringMethod?.IsEffectivelyReadOnly == true; @@ -490,6 +490,7 @@ BoundExpression makeConditionalAccess(BoundExpression receiver) objectToStringMethod), whenNullOpt: null, id: currentConditionalAccessID, + forceCopyOfNullableValueType: false, type: _compilation.GetSpecialType(SpecialType.System_String)); } diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_StringInterpolation.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_StringInterpolation.cs index 803ddfcb42236..a35c09294453d 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_StringInterpolation.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_StringInterpolation.cs @@ -75,7 +75,7 @@ private BoundExpression MakeImplicitConversionForInterpolatedString(BoundExpress private InterpolationHandlerResult RewriteToInterpolatedStringHandlerPattern(InterpolatedStringHandlerData data, ImmutableArray parts, SyntaxNode syntax) { Debug.Assert(parts.All(static p => p is BoundCall or BoundDynamicInvocation)); - var builderTempSymbol = _factory.InterpolatedStringHandlerLocal(data.BuilderType, data.ScopeOfContainingExpression, syntax); + var builderTempSymbol = _factory.InterpolatedStringHandlerLocal(data.BuilderType, syntax); BoundLocal builderTemp = _factory.Local(builderTempSymbol); // var handler = new HandlerType(baseStringLength, numFormatHoles, ...InterpolatedStringHandlerArgumentAttribute parameters, out bool appendShouldProceed); @@ -222,13 +222,13 @@ private void MakeInterpolatedStringFormat(BoundInterpolatedString node, out Boun stringBuilder.Append('{').Append(nextFormatPosition++); if (fillin.Alignment != null && !fillin.Alignment.HasErrors) { - Debug.Assert(fillin.Alignment.ConstantValue is { }); - stringBuilder.Append(',').Append(fillin.Alignment.ConstantValue.Int64Value); + Debug.Assert(fillin.Alignment.ConstantValueOpt is { }); + stringBuilder.Append(',').Append(fillin.Alignment.ConstantValueOpt.Int64Value); } if (fillin.Format != null && !fillin.Format.HasErrors) { - Debug.Assert(fillin.Format.ConstantValue is { }); - stringBuilder.Append(':').Append(fillin.Format.ConstantValue.StringValue); + Debug.Assert(fillin.Format.ConstantValueOpt is { }); + stringBuilder.Append(':').Append(fillin.Format.ConstantValueOpt.StringValue); } stringBuilder.Append('}'); var value = fillin.Value; @@ -241,10 +241,10 @@ private void MakeInterpolatedStringFormat(BoundInterpolatedString node, out Boun } else { - Debug.Assert(part is BoundLiteral && part.ConstantValue?.StringValue != null); + Debug.Assert(part is BoundLiteral && part.ConstantValueOpt?.StringValue != null); // this is one of the literal parts. If it contains a { or } then we need to escape those so that // they're treated the same way in string.Format. - stringBuilder.Append(escapeInterpolatedStringLiteral(part.ConstantValue.StringValue)); + stringBuilder.Append(escapeInterpolatedStringLiteral(part.ConstantValueOpt.StringValue)); } } @@ -310,8 +310,8 @@ public override BoundNode VisitInterpolatedString(BoundInterpolatedString node) else { // this is one of the literal parts - Debug.Assert(part is BoundLiteral && part.ConstantValue?.StringValue is not null); - part = _factory.StringLiteral(part.ConstantValue.StringValue); + Debug.Assert(part is BoundLiteral && part.ConstantValueOpt?.StringValue is not null); + part = _factory.StringLiteral(part.ConstantValueOpt.StringValue); } result = result == null ? @@ -322,7 +322,7 @@ public override BoundNode VisitInterpolatedString(BoundInterpolatedString node) // We need to ensure that the result of the interpolated string is not null. If the single part has a non-null constant value // or is itself an interpolated string (which by proxy cannot be null), then there's nothing else that needs to be done. Otherwise, // we need to test for null and ensure "" if it is. - if (length == 1 && result is not ({ Kind: BoundKind.InterpolatedString } or { ConstantValue.IsString: true })) + if (length == 1 && result is not ({ Kind: BoundKind.InterpolatedString } or { ConstantValueOpt.IsString: true })) { Debug.Assert(result is not null); Debug.Assert(result.Type is not null); diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_TryStatement.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_TryStatement.cs index c4fc941010c39..c4257dd20218d 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_TryStatement.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_TryStatement.cs @@ -82,7 +82,7 @@ private static bool HasSideEffects([NotNullWhen(true)] BoundStatement? statement return base.VisitCatchBlock(node); } - if (node.ExceptionFilterOpt.ConstantValue?.BooleanValue == false) + if (node.ExceptionFilterOpt.ConstantValueOpt?.BooleanValue == false) { return null; } diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_TupleBinaryOperator.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_TupleBinaryOperator.cs index b7ac4d97e1a61..f907ec0efa27d 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_TupleBinaryOperator.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_TupleBinaryOperator.cs @@ -185,7 +185,7 @@ private BoundExpression DeferSideEffectingArgumentToTempForTupleEquality( { switch (expr) { - case { ConstantValue: { } }: + case { ConstantValueOpt: { } }: return VisitExpression(expr); case BoundConversion { Conversion: { Kind: ConversionKind.DefaultLiteral } }: // This conversion can be performed lazily, but need not be saved. It is treated as non-side-effecting. @@ -315,7 +315,7 @@ private BoundExpression RewriteTupleNestedOperators(TupleBinaryOperatorInfo.Mult bool boolValue = operatorKind == BinaryOperatorKind.Equal; // true/false - if (rightHasValue.ConstantValue == ConstantValue.False) + if (rightHasValue.ConstantValueOpt == ConstantValue.False) { // The outer sequence degenerates when we known that `rightHasValue` is false // Produce: !leftHasValue (or leftHasValue for inequality comparison) @@ -323,7 +323,7 @@ private BoundExpression RewriteTupleNestedOperators(TupleBinaryOperatorInfo.Mult result: boolValue ? _factory.Not(leftHasValue) : leftHasValue); } - if (leftHasValue.ConstantValue == ConstantValue.False) + if (leftHasValue.ConstantValueOpt == ConstantValue.False) { // The outer sequence degenerates when we known that `leftHasValue` is false // Produce: !rightHasValue (or rightHasValue for inequality comparison) @@ -609,7 +609,7 @@ private BoundExpression LowerConversions(BoundExpression expr) ? MakeConversionNode( oldNodeOpt: conv, syntax: conv.Syntax, rewrittenOperand: LowerConversions(conv.Operand), conversion: conv.Conversion, @checked: conv.Checked, explicitCastInCode: conv.ExplicitCastInCode, - constantValueOpt: conv.ConstantValue, rewrittenType: conv.Type) + constantValueOpt: conv.ConstantValueOpt, rewrittenType: conv.Type) : expr; } } diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_TupleCreationExpression.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_TupleCreationExpression.cs index 3124adf61698d..bb097819540f2 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_TupleCreationExpression.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_TupleCreationExpression.cs @@ -100,7 +100,7 @@ private BoundExpression MakeTupleCreationExpression(SyntaxNode syntax, NamedType currentCreation.Expanded, currentCreation.ArgsToParamsOpt, currentCreation.DefaultArguments, - currentCreation.ConstantValue, + currentCreation.ConstantValueOpt, currentCreation.InitializerExpressionOpt, type); diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_UnaryOperator.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_UnaryOperator.cs index 5322b5b2f0373..8477313b56b13 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_UnaryOperator.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_UnaryOperator.cs @@ -276,6 +276,7 @@ private BoundExpression LowerLiftedUnaryOperator( whenNotNull: result, whenNullOpt: null, id: conditionalLeft.Id, + forceCopyOfNullableValueType: conditionalLeft.ForceCopyOfNullableValueType, type: result.Type ); } diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_UsingStatement.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_UsingStatement.cs index 69cbb5f07bf4e..ff39cc858837a 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_UsingStatement.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_UsingStatement.cs @@ -124,7 +124,7 @@ private BoundBlock MakeExpressionUsingStatement(BoundUsingStatement node, BoundB // If expr is the constant null then we can elide the whole thing and simply generate the statement. BoundExpression rewrittenExpression = VisitExpression(node.ExpressionOpt); - if (rewrittenExpression.ConstantValue == ConstantValue.Null) + if (rewrittenExpression.ConstantValueOpt == ConstantValue.Null) { Debug.Assert(node.Locals.IsEmpty); // TODO: This might not be a valid assumption in presence of semicolon operator. return tryBlock; @@ -170,7 +170,7 @@ private BoundBlock MakeExpressionUsingStatement(BoundUsingStatement node, BoundB Conversion.ImplicitDynamic, iDisposableType, @checked: false, - constantValueOpt: rewrittenExpression.ConstantValue); + constantValueOpt: rewrittenExpression.ConstantValueOpt); boundTemp = _factory.StoreToTemp(tempInit, out tempAssignment, kind: SynthesizedLocalKind.Using); } @@ -217,7 +217,7 @@ private BoundBlock RewriteDeclarationUsingStatement( TypeSymbol localType = localSymbol.Type; Debug.Assert((object)localType != null); //otherwise, there wouldn't be a conversion to IDisposable - BoundLocal boundLocal = new BoundLocal(declarationSyntax, localSymbol, localDeclaration.InitializerOpt.ConstantValue, localType); + BoundLocal boundLocal = new BoundLocal(declarationSyntax, localSymbol, localDeclaration.InitializerOpt.ConstantValueOpt, localType); BoundStatement? rewrittenDeclaration = VisitStatement(localDeclaration); Debug.Assert(rewrittenDeclaration is { }); @@ -226,7 +226,7 @@ private BoundBlock RewriteDeclarationUsingStatement( // will fail, and the Dispose call will never happen. That is, the finally block will have no effect. // Consequently, we can simply skip the whole try-finally construct and just create a block containing // the new declaration. - if (boundLocal.ConstantValue == ConstantValue.Null) + if (boundLocal.ConstantValueOpt == ConstantValue.Null) { //localSymbol will be declared by an enclosing block return BoundBlock.SynthesizedNoLocals(declarationSyntax, rewrittenDeclaration, tryBlock); diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LoweredDynamicOperationFactory.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LoweredDynamicOperationFactory.cs index 62bd64e213a9b..46154cae09e51 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LoweredDynamicOperationFactory.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LoweredDynamicOperationFactory.cs @@ -863,7 +863,7 @@ private BoundExpression GetArgumentInfo( // // as well as the alternative where x is a const null of type object. - if (boundArgument.ConstantValue != null) + if (boundArgument.ConstantValueOpt != null) { flags |= CSharpArgumentInfoFlags.Constant; } diff --git a/src/Compilers/CSharp/Portable/Lowering/MethodToClassRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/MethodToClassRewriter.cs index bcf1bbbab422b..0a5d8bcafa4e3 100644 --- a/src/Compilers/CSharp/Portable/Lowering/MethodToClassRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/MethodToClassRewriter.cs @@ -150,7 +150,7 @@ public override BoundNode VisitBlock(BoundBlock node) var newLocals = RewriteLocals(node.Locals); var newLocalFunctions = node.LocalFunctions; var newStatements = VisitList(node.Statements); - return node.Update(newLocals, newLocalFunctions, newStatements); + return node.Update(newLocals, newLocalFunctions, node.HasUnsafeModifier, newStatements); } public abstract override BoundNode VisitScope(BoundScope node); @@ -258,7 +258,7 @@ public override BoundNode VisitBinaryOperator(BoundBinaryOperator node) return node.Update( node.OperatorKind, - node.ConstantValue, + node.ConstantValueOpt, VisitMethodSymbol(node.Method), VisitType(node.ConstrainedToType), node.ResultKind, @@ -417,7 +417,7 @@ public override BoundNode VisitAwaitableInfo(BoundAwaitableInfo node) return node; } - var rewrittenPlaceholder = awaitablePlaceholder.Update(awaitablePlaceholder.ValEscape, VisitType(awaitablePlaceholder.Type)); + var rewrittenPlaceholder = awaitablePlaceholder.Update(VisitType(awaitablePlaceholder.Type)); _placeholderMap.Add(awaitablePlaceholder, rewrittenPlaceholder); var getAwaiter = (BoundExpression?)this.Visit(node.GetAwaiter); @@ -566,7 +566,7 @@ public override BoundNode VisitLoweredConditionalAccess(BoundLoweredConditionalA var whenNotNull = (BoundExpression)this.Visit(node.WhenNotNull); var whenNullOpt = (BoundExpression?)this.Visit(node.WhenNullOpt); TypeSymbol type = this.VisitType(node.Type); - return node.Update(receiver, VisitMethodSymbol(node.HasValueMethodOpt), whenNotNull, whenNullOpt, node.Id, type); + return node.Update(receiver, VisitMethodSymbol(node.HasValueMethodOpt), whenNotNull, whenNullOpt, node.Id, node.ForceCopyOfNullableValueType, type); } [return: NotNullIfNotNull(nameof(method))] diff --git a/src/Compilers/CSharp/Portable/Lowering/SpillSequenceSpiller.cs b/src/Compilers/CSharp/Portable/Lowering/SpillSequenceSpiller.cs index 5821fda613662..a7ecfc1939d9d 100644 --- a/src/Compilers/CSharp/Portable/Lowering/SpillSequenceSpiller.cs +++ b/src/Compilers/CSharp/Portable/Lowering/SpillSequenceSpiller.cs @@ -21,12 +21,12 @@ internal sealed class SpillSequenceSpiller : BoundTreeRewriterWithStackGuard private readonly SyntheticBoundNodeFactory _F; private readonly PooledDictionary _tempSubstitution; - private readonly PooledDictionary _receiverSubstitution; + private readonly PooledDictionary _receiverSubstitution; private SpillSequenceSpiller( MethodSymbol method, SyntaxNode syntaxNode, TypeCompilationState compilationState, PooledDictionary tempSubstitution, - PooledDictionary receiverSubstitution, + PooledDictionary receiverSubstitution, BindingDiagnosticBag diagnostics) { _F = new SyntheticBoundNodeFactory(method, syntaxNode, compilationState, diagnostics); @@ -182,11 +182,11 @@ internal override string Dump() private sealed class LocalSubstituter : BoundTreeRewriterWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator { private readonly PooledDictionary _tempSubstitution; - private readonly PooledDictionary _receiverSubstitution; + private readonly PooledDictionary _receiverSubstitution; private LocalSubstituter( PooledDictionary tempSubstitution, - PooledDictionary receiverSubstitution, + PooledDictionary receiverSubstitution, int recursionDepth = 0) : base(recursionDepth) { @@ -196,7 +196,7 @@ private LocalSubstituter( public static BoundNode Rewrite( PooledDictionary tempSubstitution, - PooledDictionary receiverSubstitution, + PooledDictionary receiverSubstitution, BoundNode node) { if (tempSubstitution.Count == 0) @@ -233,7 +233,7 @@ public override BoundNode VisitLocal(BoundLocal node) internal static BoundStatement Rewrite(BoundStatement body, MethodSymbol method, TypeCompilationState compilationState, BindingDiagnosticBag diagnostics) { var tempSubstitution = PooledDictionary.GetInstance(); - var receiverSubstitution = PooledDictionary.GetInstance(); + var receiverSubstitution = PooledDictionary.GetInstance(); var spiller = new SpillSequenceSpiller(method, body.Syntax, compilationState, tempSubstitution, receiverSubstitution, diagnostics); BoundNode result = spiller.Visit(body); result = LocalSubstituter.Rewrite(tempSubstitution, receiverSubstitution, result); @@ -356,15 +356,14 @@ private BoundExpression Spill( IsComplexConditionalInitializationOfReceiverRef( assignment, out LocalSymbol receiverRefLocal, - out BoundBinaryOperator isValueTypeCheck, - out BoundAssignmentOperator referenceTypeReceiverCloning, + out BoundComplexReceiver complexReceiver, out BoundLocal valueTypeReceiver, out BoundLocal referenceTypeReceiver)) { Debug.Assert(receiverRefLocal.IsKnownToReferToTempIfReferenceType); - builder.AddStatement(_F.If(_F.Not(isValueTypeCheck), _F.ExpressionStatement(referenceTypeReceiverCloning))); + builder.AddStatement(_F.ExpressionStatement(complexReceiver)); - _receiverSubstitution.Add(receiverRefLocal, _F.ComplexConditionalReceiver(valueTypeReceiver, referenceTypeReceiver)); + _receiverSubstitution.Add(receiverRefLocal, complexReceiver.Update(valueTypeReceiver, referenceTypeReceiver, complexReceiver.Type)); return null; } else @@ -458,8 +457,7 @@ private BoundExpression Spill( internal static bool IsComplexConditionalInitializationOfReceiverRef( BoundAssignmentOperator assignment, out LocalSymbol outReceiverRefLocal, - out BoundBinaryOperator outIsValueTypeCheck, - out BoundAssignmentOperator outReferenceTypeReceiverCloning, + out BoundComplexReceiver outComplexReceiver, out BoundLocal outValueTypeReceiver, out BoundLocal outReferenceTypeReceiver) { @@ -467,24 +465,10 @@ internal static bool IsComplexConditionalInitializationOfReceiverRef( { IsRef: true, Left: BoundLocal { LocalSymbol: { SynthesizedKind: SynthesizedLocalKind.LoweringTemp, RefKind: RefKind.Ref } receiverRefLocal }, - Right: BoundConditionalOperator + Right: BoundComplexReceiver { - IsRef: true, - Condition: BoundBinaryOperator - { - OperatorKind: BinaryOperatorKind.ObjectNotEqual, - Left: BoundConversion - { - Conversion: { IsUserDefined: false }, - Operand: BoundDefaultExpression { Type: var typeOfDefault }, - Type.SpecialType: SpecialType.System_Object - }, - Right: BoundLiteral { ConstantValue.IsNull: true, Type.SpecialType: SpecialType.System_Object } - } isValueTypeCheck, - - Consequence: BoundLocal { LocalSymbol: { SynthesizedKind: SynthesizedLocalKind.LoweringTemp, RefKind: RefKind.Ref } } valueTypeReceiver, - - Alternative: BoundSequence + ValueTypeReceiver: BoundLocal { LocalSymbol: { SynthesizedKind: SynthesizedLocalKind.LoweringTemp, RefKind: RefKind.Ref } } valueTypeReceiver, + ReferenceTypeReceiver: BoundSequence { Locals.IsEmpty: true, SideEffects: @@ -494,11 +478,11 @@ internal static bool IsComplexConditionalInitializationOfReceiverRef( IsRef: false, Left: BoundLocal { LocalSymbol: { SynthesizedKind: SynthesizedLocalKind.LoweringTemp, RefKind: RefKind.None } referenceTypeClone }, Right: BoundLocal { LocalSymbol: { SynthesizedKind: SynthesizedLocalKind.LoweringTemp, RefKind: RefKind.Ref } originalReceiverReference } - } referenceTypeReceiverCloning + } ], Value: BoundLocal { LocalSymbol: { SynthesizedKind: SynthesizedLocalKind.LoweringTemp, RefKind: RefKind.None } } referenceTypeReceiver } - } + } complexReceiver, } && (object)referenceTypeClone == referenceTypeReceiver.LocalSymbol && (object)originalReceiverReference == valueTypeReceiver.LocalSymbol @@ -507,22 +491,19 @@ internal static bool IsComplexConditionalInitializationOfReceiverRef( && receiverRefLocal.Type.IsTypeParameter() && !receiverRefLocal.Type.IsReferenceType && !receiverRefLocal.Type.IsValueType - && typeOfDefault.Equals(receiverRefLocal.Type, TypeCompareKind.AllIgnoreOptions) && valueTypeReceiver.Type.Equals(receiverRefLocal.Type, TypeCompareKind.AllIgnoreOptions) && referenceTypeReceiver.Type.Equals(receiverRefLocal.Type, TypeCompareKind.AllIgnoreOptions) ) { outReceiverRefLocal = receiverRefLocal; - outIsValueTypeCheck = isValueTypeCheck; - outReferenceTypeReceiverCloning = referenceTypeReceiverCloning; + outComplexReceiver = complexReceiver; outValueTypeReceiver = valueTypeReceiver; outReferenceTypeReceiver = referenceTypeReceiver; return true; } outReceiverRefLocal = null; - outIsValueTypeCheck = null; - outReferenceTypeReceiverCloning = null; + outComplexReceiver = null; outValueTypeReceiver = null; outReferenceTypeReceiver = null; return false; @@ -958,7 +939,7 @@ public override BoundNode VisitBinaryOperator(BoundBinaryOperator node) } } - return UpdateExpression(builder, node.Update(node.OperatorKind, node.ConstantValue, node.Method, node.ConstrainedToType, node.ResultKind, left, right, node.Type)); + return UpdateExpression(builder, node.Update(node.OperatorKind, node.ConstantValueOpt, node.Method, node.ConstrainedToType, node.ResultKind, left, right, node.Type)); } public override BoundNode VisitCall(BoundCall node) @@ -998,17 +979,15 @@ public override BoundNode VisitCall(BoundCall node) // reference to the stack. So, for a class we need to emit a reference to a temporary // location, rather than to the original location - // If condition `(object)default(T) != null` is true at execution time, - // the T is a value type. And it is a reference type otherwise. - var isValueTypeCheck = _F.ObjectNotEqual( - _F.Convert(_F.SpecialType(SpecialType.System_Object), _F.Default(receiverType)), - _F.Null(_F.SpecialType(SpecialType.System_Object))); + var save_Syntax = _F.Syntax; + _F.Syntax = node.Syntax; var cache = _F.Local(_F.SynthesizedLocal(receiverType)); receiverBuilder.AddLocal(cache.LocalSymbol); - receiverBuilder.AddStatement(_F.If(_F.Not(isValueTypeCheck), _F.Assignment(cache, receiver))); + receiverBuilder.AddStatement(_F.ExpressionStatement(new BoundComplexReceiver(node.Syntax, cache, _F.Sequence(new[] { _F.AssignmentExpression(cache, receiver) }, cache), receiverType) { WasCompilerGenerated = true })); - receiver = _F.ComplexConditionalReceiver(receiver, cache); + receiver = new BoundComplexReceiver(node.Syntax, receiver, cache, receiverType) { WasCompilerGenerated = true }; + _F.Syntax = save_Syntax; } receiverBuilder.Include(builder); @@ -1198,7 +1177,7 @@ public override BoundNode VisitLoweredConditionalAccess(BoundLoweredConditionalA if (whenNotNullBuilder == null && whenNullBuilder == null) { - return UpdateExpression(receiverBuilder, node.Update(receiver, node.HasValueMethodOpt, whenNotNull, whenNullOpt, node.Id, node.Type)); + return UpdateExpression(receiverBuilder, node.Update(receiver, node.HasValueMethodOpt, whenNotNull, whenNullOpt, node.Id, node.ForceCopyOfNullableValueType, node.Type)); } if (receiverBuilder == null) receiverBuilder = new BoundSpillSequenceBuilder((whenNotNullBuilder ?? whenNullBuilder).Syntax); diff --git a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/MethodToStateMachineRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/MethodToStateMachineRewriter.cs index ae5a282273037..a35b9ed5e30b3 100644 --- a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/MethodToStateMachineRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/MethodToStateMachineRewriter.cs @@ -623,7 +623,7 @@ private BoundExpression HoistExpression( goto default; default: - if (expr.ConstantValue != null) + if (expr.ConstantValueOpt != null) { return expr; } diff --git a/src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs b/src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs index 63cd04fbbb7cd..51e4ab4305795 100644 --- a/src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs +++ b/src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs @@ -466,7 +466,7 @@ public BoundBlock Block(ImmutableArray locals, ImmutableArray locals, ImmutableArray localFunctions, ImmutableArray statements) { - return new BoundBlock(Syntax, locals, localFunctions, statements) { WasCompilerGenerated = true }; + return new BoundBlock(Syntax, locals, localFunctions, hasUnsafeModifier: false, statements) { WasCompilerGenerated = true }; } public BoundExtractedFinallyBlock ExtractedFinallyBlock(BoundBlock finallyBlock) @@ -551,7 +551,6 @@ public LocalSymbol SynthesizedLocal( public LocalSymbol InterpolatedStringHandlerLocal( TypeSymbol type, - uint valEscapeScope, SyntaxNode syntax #if DEBUG , @@ -560,11 +559,10 @@ SyntaxNode syntax #endif ) { - return new SynthesizedLocalWithValEscape( + return new SynthesizedLocal( CurrentFunction, TypeWithAnnotations.Create(type), SynthesizedLocalKind.LoweringTemp, - valEscapeScope, syntax #if DEBUG , createdAtLineNumber: createdAtLineNumber, createdAtFilePath: createdAtFilePath @@ -1585,14 +1583,14 @@ internal BoundExpression MakeNullCheck(SyntaxNode syntax, BoundExpression rewrit TypeSymbol boolType = Compilation.GetSpecialType(CodeAnalysis.SpecialType.System_Boolean); // Fold compile-time comparisons. - if (rewrittenExpr.ConstantValue != null) + if (rewrittenExpr.ConstantValueOpt != null) { switch (operatorKind) { case BinaryOperatorKind.Equal: - return Literal(ConstantValue.Create(rewrittenExpr.ConstantValue.IsNull, ConstantValueTypeDiscriminator.Boolean), boolType); + return Literal(ConstantValue.Create(rewrittenExpr.ConstantValueOpt.IsNull, ConstantValueTypeDiscriminator.Boolean), boolType); case BinaryOperatorKind.NotEqual: - return Literal(ConstantValue.Create(rewrittenExpr.ConstantValue.IsNull, ConstantValueTypeDiscriminator.Boolean), boolType); + return Literal(ConstantValue.Create(rewrittenExpr.ConstantValueOpt.IsNull, ConstantValueTypeDiscriminator.Boolean), boolType); } } @@ -1687,7 +1685,7 @@ internal BoundExpression RewriteNullableNullEquality( var whenNull = kind == BinaryOperatorKind.NullableNullEqual ? Literal(true) : null; - return conditionalAccess.Update(conditionalAccess.Receiver, conditionalAccess.HasValueMethodOpt, whenNotNull, whenNull, conditionalAccess.Id, whenNotNull.Type); + return conditionalAccess.Update(conditionalAccess.Receiver, conditionalAccess.HasValueMethodOpt, whenNotNull, whenNull, conditionalAccess.Id, conditionalAccess.ForceCopyOfNullableValueType, whenNotNull.Type); } BoundExpression call = MakeNullableHasValue(syntax, nullable); diff --git a/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs b/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs index e682d4bb7ccc5..be08becf4ceca 100644 --- a/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs +++ b/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs @@ -301,7 +301,7 @@ public CSharpOperationFactory(SemanticModel semanticModel) case BoundKind.TypeExpression: case BoundKind.TypeOrValueExpression: - ConstantValue? constantValue = (boundNode as BoundExpression)?.ConstantValue; + ConstantValue? constantValue = (boundNode as BoundExpression)?.ConstantValueOpt; bool isImplicit = boundNode.WasCompilerGenerated; if (!isImplicit) @@ -439,7 +439,7 @@ private IOperation CreateBoundCallOperation(BoundCall boundCall) MethodSymbol targetMethod = boundCall.Method; SyntaxNode syntax = boundCall.Syntax; ITypeSymbol? type = boundCall.GetPublicTypeSymbol(); - ConstantValue? constantValue = boundCall.ConstantValue; + ConstantValue? constantValue = boundCall.ConstantValueOpt; bool isImplicit = boundCall.WasCompilerGenerated; if (!boundCall.OriginalMethodsOpt.IsDefault || IsMethodInvalid(boundCall.ResultKind, targetMethod)) @@ -510,7 +510,7 @@ private IOperation CreateBoundAttributeOperation(BoundAttribute boundAttribute) Debug.Assert(initializer.Initializers.All(i => i is ISimpleAssignmentOperation)); } - var objectCreationOperation = new ObjectCreationOperation(boundAttribute.Constructor.GetPublicSymbol(), initializer, DeriveArguments(boundAttribute), _semanticModel, boundAttribute.Syntax, boundAttribute.GetPublicTypeSymbol(), boundAttribute.ConstantValue, isImplicit: true); + var objectCreationOperation = new ObjectCreationOperation(boundAttribute.Constructor.GetPublicSymbol(), initializer, DeriveArguments(boundAttribute), _semanticModel, boundAttribute.Syntax, boundAttribute.GetPublicTypeSymbol(), boundAttribute.ConstantValueOpt, isImplicit: true); return new AttributeOperation(objectCreationOperation, _semanticModel, boundAttribute.Syntax, isAttributeImplicit); } @@ -552,7 +552,7 @@ internal IOperation CreateBoundLocalOperation(BoundLocal boundLocal, bool create bool isDeclaration = boundLocal.DeclarationKind != BoundLocalDeclarationKind.None; SyntaxNode syntax = boundLocal.Syntax; ITypeSymbol? type = boundLocal.GetPublicTypeSymbol(); - ConstantValue? constantValue = boundLocal.ConstantValue; + ConstantValue? constantValue = boundLocal.ConstantValueOpt; bool isImplicit = boundLocal.WasCompilerGenerated; if (isDeclaration && syntax is DeclarationExpressionSyntax declarationExpressionSyntax) { @@ -572,7 +572,7 @@ internal IOperation CreateBoundFieldAccessOperation(BoundFieldAccess boundFieldA bool isDeclaration = boundFieldAccess.IsDeclaration; SyntaxNode syntax = boundFieldAccess.Syntax; ITypeSymbol? type = boundFieldAccess.GetPublicTypeSymbol(); - ConstantValue? constantValue = boundFieldAccess.ConstantValue; + ConstantValue? constantValue = boundFieldAccess.ConstantValueOpt; bool isImplicit = boundFieldAccess.WasCompilerGenerated; if (isDeclaration && syntax is DeclarationExpressionSyntax declarationExpressionSyntax) { @@ -672,7 +672,7 @@ internal ILiteralOperation CreateBoundLiteralOperation(BoundLiteral boundLiteral { SyntaxNode syntax = boundLiteral.Syntax; ITypeSymbol? type = boundLiteral.GetPublicTypeSymbol(); - ConstantValue? constantValue = boundLiteral.ConstantValue; + ConstantValue? constantValue = boundLiteral.ConstantValueOpt; bool isImplicit = boundLiteral.WasCompilerGenerated || @implicit; return new LiteralOperation(_semanticModel, syntax, type, constantValue, isImplicit); } @@ -700,7 +700,7 @@ private IOperation CreateBoundObjectCreationExpressionOperation(BoundObjectCreat MethodSymbol constructor = boundObjectCreationExpression.Constructor; SyntaxNode syntax = boundObjectCreationExpression.Syntax; ITypeSymbol? type = boundObjectCreationExpression.GetPublicTypeSymbol(); - ConstantValue? constantValue = boundObjectCreationExpression.ConstantValue; + ConstantValue? constantValue = boundObjectCreationExpression.ConstantValueOpt; bool isImplicit = boundObjectCreationExpression.WasCompilerGenerated; Debug.Assert(constructor is not null); @@ -921,7 +921,7 @@ private IOperation CreateBoundCollectionElementInitializerOperation(BoundCollect ImmutableArray arguments = DeriveArguments(boundCollectionElementInitializer); SyntaxNode syntax = boundCollectionElementInitializer.Syntax; ITypeSymbol? type = boundCollectionElementInitializer.GetPublicTypeSymbol(); - ConstantValue? constantValue = boundCollectionElementInitializer.ConstantValue; + ConstantValue? constantValue = boundCollectionElementInitializer.ConstantValueOpt; bool isImplicit = boundCollectionElementInitializer.WasCompilerGenerated; if (IsMethodInvalid(boundCollectionElementInitializer.ResultKind, addMethod)) @@ -1106,7 +1106,7 @@ private IOperation CreateBoundConversionOperation(BoundConversion boundConversio } ITypeSymbol? type = boundConversion.GetPublicTypeSymbol(); - ConstantValue? constantValue = boundConversion.ConstantValue; + ConstantValue? constantValue = boundConversion.ConstantValueOpt; // If this is a lambda or method group conversion to a delegate type, we return a delegate creation instead of a conversion if ((boundOperand.Kind == BoundKind.Lambda || @@ -1180,7 +1180,7 @@ private ISizeOfOperation CreateBoundSizeOfOperatorOperation(BoundSizeOfOperator Debug.Assert(typeOperand is not null); SyntaxNode syntax = boundSizeOfOperator.Syntax; ITypeSymbol? type = boundSizeOfOperator.GetPublicTypeSymbol(); - ConstantValue? constantValue = boundSizeOfOperator.ConstantValue; + ConstantValue? constantValue = boundSizeOfOperator.ConstantValueOpt; bool isImplicit = boundSizeOfOperator.WasCompilerGenerated; return new SizeOfOperation(typeOperand, _semanticModel, syntax, type, constantValue, isImplicit); } @@ -1217,7 +1217,7 @@ private IArrayInitializerOperation CreateBoundArrayInitializationOperation(Bound private IDefaultValueOperation CreateBoundDefaultLiteralOperation(BoundDefaultLiteral boundDefaultLiteral) { SyntaxNode syntax = boundDefaultLiteral.Syntax; - ConstantValue? constantValue = boundDefaultLiteral.ConstantValue; + ConstantValue? constantValue = boundDefaultLiteral.ConstantValueOpt; bool isImplicit = boundDefaultLiteral.WasCompilerGenerated; return new DefaultValueOperation(_semanticModel, syntax, type: null, constantValue, isImplicit); } @@ -1226,7 +1226,7 @@ private IDefaultValueOperation CreateBoundDefaultExpressionOperation(BoundDefaul { SyntaxNode syntax = boundDefaultExpression.Syntax; ITypeSymbol? type = boundDefaultExpression.GetPublicTypeSymbol(); - ConstantValue? constantValue = boundDefaultExpression.ConstantValue; + ConstantValue? constantValue = ((BoundExpression)boundDefaultExpression).ConstantValueOpt; bool isImplicit = boundDefaultExpression.WasCompilerGenerated; return new DefaultValueOperation(_semanticModel, syntax, type, constantValue, isImplicit); } @@ -1269,7 +1269,7 @@ private ISimpleAssignmentOperation CreateBoundAssignmentOperatorOperation(BoundA bool isRef = boundAssignmentOperator.IsRef; SyntaxNode syntax = boundAssignmentOperator.Syntax; ITypeSymbol? type = boundAssignmentOperator.GetPublicTypeSymbol(); - ConstantValue? constantValue = boundAssignmentOperator.ConstantValue; + ConstantValue? constantValue = boundAssignmentOperator.ConstantValueOpt; bool isImplicit = boundAssignmentOperator.WasCompilerGenerated; return new SimpleAssignmentOperation(isRef, target, value, _semanticModel, syntax, type, constantValue, isImplicit); } @@ -1368,7 +1368,7 @@ private IUnaryOperation CreateBoundUnaryOperatorOperation(BoundUnaryOperator bou IMethodSymbol? operatorMethod = boundUnaryOperator.MethodOpt.GetPublicSymbol(); SyntaxNode syntax = boundUnaryOperator.Syntax; ITypeSymbol? type = boundUnaryOperator.GetPublicTypeSymbol(); - ConstantValue? constantValue = boundUnaryOperator.ConstantValue; + ConstantValue? constantValue = boundUnaryOperator.ConstantValueOpt; bool isLifted = boundUnaryOperator.OperatorKind.IsLifted(); bool isChecked = boundUnaryOperator.OperatorKind.IsChecked() || (boundUnaryOperator.MethodOpt is not null && SyntaxFacts.IsCheckedOperator(boundUnaryOperator.MethodOpt.Name)); bool isImplicit = boundUnaryOperator.WasCompilerGenerated; @@ -1422,7 +1422,7 @@ IBinaryOperation createBoundUserDefinedConditionalLogicalOperator(BoundUserDefin boundBinaryOperator.TrueOperator.GetPublicSymbol(); SyntaxNode syntax = boundBinaryOperator.Syntax; ITypeSymbol? type = boundBinaryOperator.GetPublicTypeSymbol(); - ConstantValue? constantValue = boundBinaryOperator.ConstantValue; + ConstantValue? constantValue = boundBinaryOperator.ConstantValueOpt; bool isLifted = boundBinaryOperator.OperatorKind.IsLifted(); bool isChecked = boundBinaryOperator.OperatorKind.IsChecked(); bool isCompareText = false; @@ -1454,7 +1454,7 @@ private IBinaryOperation CreateBoundBinaryOperatorOperation(BoundBinaryOperator SyntaxNode syntax = boundBinaryOperator.Syntax; ITypeSymbol? type = boundBinaryOperator.GetPublicTypeSymbol(); - ConstantValue? constantValue = boundBinaryOperator.ConstantValue; + ConstantValue? constantValue = boundBinaryOperator.ConstantValueOpt; bool isLifted = boundBinaryOperator.OperatorKind.IsLifted(); bool isChecked = boundBinaryOperator.OperatorKind.IsChecked() || (boundBinaryOperator.Method is not null && SyntaxFacts.IsCheckedOperator(boundBinaryOperator.Method.Name)); bool isCompareText = false; @@ -1510,7 +1510,7 @@ private IConditionalOperation CreateBoundConditionalOperatorOperation(BoundCondi bool isRef = boundConditionalOperator.IsRef; SyntaxNode syntax = boundConditionalOperator.Syntax; ITypeSymbol? type = boundConditionalOperator.GetPublicTypeSymbol(); - ConstantValue? constantValue = boundConditionalOperator.ConstantValue; + ConstantValue? constantValue = boundConditionalOperator.ConstantValueOpt; bool isImplicit = boundConditionalOperator.WasCompilerGenerated; return new ConditionalOperation(condition, whenTrue, whenFalse, isRef, _semanticModel, syntax, type, constantValue, isImplicit); } @@ -1521,7 +1521,7 @@ private ICoalesceOperation CreateBoundNullCoalescingOperatorOperation(BoundNullC IOperation whenNull = Create(boundNullCoalescingOperator.RightOperand); SyntaxNode syntax = boundNullCoalescingOperator.Syntax; ITypeSymbol? type = boundNullCoalescingOperator.GetPublicTypeSymbol(); - ConstantValue? constantValue = boundNullCoalescingOperator.ConstantValue; + ConstantValue? constantValue = boundNullCoalescingOperator.ConstantValueOpt; bool isImplicit = boundNullCoalescingOperator.WasCompilerGenerated; Conversion valueConversion = BoundNode.GetConversion(boundNullCoalescingOperator.LeftConversion, boundNullCoalescingOperator.LeftPlaceholder); @@ -1592,7 +1592,7 @@ private INameOfOperation CreateBoundNameOfOperatorOperation(BoundNameOfOperator IOperation argument = Create(boundNameOfOperator.Argument); SyntaxNode syntax = boundNameOfOperator.Syntax; ITypeSymbol? type = boundNameOfOperator.GetPublicTypeSymbol(); - ConstantValue constantValue = boundNameOfOperator.ConstantValue; + ConstantValue constantValue = boundNameOfOperator.ConstantValueOpt; bool isImplicit = boundNameOfOperator.WasCompilerGenerated; return new NameOfOperation(argument, _semanticModel, syntax, type, constantValue, isImplicit); } @@ -2146,7 +2146,7 @@ private IInterpolatedStringOperation CreateBoundInterpolatedStringExpressionOper ImmutableArray parts = CreateBoundInterpolatedStringContentOperation(boundInterpolatedString.Parts, positionInfo ?? boundInterpolatedString.InterpolationData?.PositionInfo[0]); SyntaxNode syntax = boundInterpolatedString.Syntax; ITypeSymbol? type = boundInterpolatedString.GetPublicTypeSymbol(); - ConstantValue? constantValue = boundInterpolatedString.ConstantValue; + ConstantValue? constantValue = boundInterpolatedString.ConstantValueOpt; bool isImplicit = boundInterpolatedString.WasCompilerGenerated; return new InterpolatedStringOperation(parts, _semanticModel, syntax, type, constantValue, isImplicit); } @@ -2352,7 +2352,7 @@ static IInterpolatedStringContentOperation (part, @this) => _semanticModel, interpolatedString.Syntax, interpolatedString.GetPublicTypeSymbol(), - interpolatedString.ConstantValue, + interpolatedString.ConstantValueOpt, isImplicit: interpolatedString.WasCompilerGenerated); default: @@ -2369,7 +2369,7 @@ private IOperation CreateBoundInterpolatedStringArgumentPlaceholder(BoundInterpo if (placeholder.ArgumentIndex == BoundInterpolatedStringArgumentPlaceholder.UnspecifiedParameter) { - return new InvalidOperation(ImmutableArray.Empty, _semanticModel, syntax, type, placeholder.ConstantValue, isImplicit); + return new InvalidOperation(ImmutableArray.Empty, _semanticModel, syntax, type, placeholder.ConstantValueOpt, isImplicit); } const int NonArgumentIndex = -1; diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs index 66cd08f12bc70..bcc362ce842ef 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs @@ -9784,11 +9784,30 @@ bool shouldTreatAsModifier() using var _ = this.GetDisposableResetPoint(resetOnDispose: true); Debug.Assert(this.CurrentToken.Kind == SyntaxKind.IdentifierToken); - this.EatToken(); - return IsDeclarationModifier(this.CurrentToken.Kind) || - IsAdditionalLocalFunctionModifier(this.CurrentToken.Kind) || - (ScanType() != ScanTypeFlags.NotType && this.CurrentToken.Kind == SyntaxKind.IdentifierToken); + do + { + this.EatToken(); + + if (IsDeclarationModifier(this.CurrentToken.Kind) || + IsAdditionalLocalFunctionModifier(this.CurrentToken.Kind)) + { + return true; + } + + using var _2 = this.GetDisposableResetPoint(resetOnDispose: true); + + if (ScanType() != ScanTypeFlags.NotType && this.CurrentToken.Kind == SyntaxKind.IdentifierToken) + { + return true; + } + } + // If current token might be a contextual modifier we need to check ahead the next token after it + // If the next token appears to be a modifier, we treat current token as a modifier as well + // This allows to correctly parse things like local functions with several `async` modifiers + while (IsAdditionalLocalFunctionModifier(this.CurrentToken.ContextualKind)); + + return false; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeDescriptor.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeDescriptor.cs index c438bdbce28ab..b6a807e6393ab 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeDescriptor.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeDescriptor.cs @@ -64,7 +64,7 @@ public bool Equals(AnonymousTypeDescriptor desc) } /// - /// Compares two anonymous type descriptors, takes into account fields names and types, not locations. + /// Compares two anonymous type descriptors, takes into account fields and types, not locations. /// internal bool Equals(AnonymousTypeDescriptor other, TypeCompareKind comparison) { @@ -78,11 +78,11 @@ internal bool Equals(AnonymousTypeDescriptor other, TypeCompareKind comparison) return Fields.SequenceEqual( other.Fields, comparison, - static (x, y, comparison) => x.TypeWithAnnotations.Equals(y.TypeWithAnnotations, comparison) && x.RefKind == y.RefKind && x.Scope == y.Scope && x.DefaultValue == y.DefaultValue && x.IsParams == y.IsParams); + static (x, y, comparison) => AnonymousTypeField.Equals(x, y, comparison)); } /// - /// Compares two anonymous type descriptors, takes into account fields names and types, not locations. + /// Compares two anonymous type descriptors, takes into account fields and types, not locations. /// public override bool Equals(object? obj) { @@ -103,7 +103,7 @@ internal AnonymousTypeDescriptor WithNewFieldsTypes(ImmutableArray new AnonymousTypeField(field.Name, field.Location, type, field.RefKind, field.Scope, field.DefaultValue, field.IsParams)); + var newFields = Fields.ZipAsArray(newFieldTypes, static (field, type) => field.WithType(type)); return new AnonymousTypeDescriptor(newFields, this.Location); } diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeField.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeField.cs index c843eb58bd577..06d8968093dcb 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeField.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeField.cs @@ -22,16 +22,26 @@ internal readonly struct AnonymousTypeField public readonly RefKind RefKind; - public readonly DeclarationScope Scope; + public readonly ScopedKind Scope; public readonly ConstantValue? DefaultValue; public readonly bool IsParams; + public readonly bool HasUnscopedRefAttribute; + /// Anonymous type field type public TypeSymbol Type => TypeWithAnnotations.Type; - public AnonymousTypeField(string name, Location location, TypeWithAnnotations typeWithAnnotations, RefKind refKind, DeclarationScope scope, ConstantValue? defaultValue = null, bool isParams = false) + public AnonymousTypeField( + string name, + Location location, + TypeWithAnnotations typeWithAnnotations, + RefKind refKind, + ScopedKind scope, + ConstantValue? defaultValue = null, + bool isParams = false, + bool hasUnscopedRefAttribute = false) { this.Name = name; this.Location = location; @@ -40,6 +50,22 @@ public AnonymousTypeField(string name, Location location, TypeWithAnnotations ty this.Scope = scope; this.DefaultValue = defaultValue; this.IsParams = isParams; + this.HasUnscopedRefAttribute = hasUnscopedRefAttribute; + } + + public AnonymousTypeField WithType(TypeWithAnnotations type) + { + return new AnonymousTypeField(Name, Location, type, RefKind, Scope, DefaultValue, IsParams, HasUnscopedRefAttribute); + } + + internal static bool Equals(in AnonymousTypeField x, in AnonymousTypeField y, TypeCompareKind comparison) + { + return x.TypeWithAnnotations.Equals(y.TypeWithAnnotations, comparison) + && x.RefKind == y.RefKind + && x.Scope == y.Scope + && x.DefaultValue == y.DefaultValue + && x.IsParams == y.IsParams + && x.HasUnscopedRefAttribute == y.HasUnscopedRefAttribute; } [Conditional("DEBUG")] diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeManager.Templates.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeManager.Templates.cs index 4950ca2f7ef9a..7dbbb327525ac 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeManager.Templates.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeManager.Templates.cs @@ -309,10 +309,14 @@ static bool allValidTypeArguments(bool useUpdatedEscapeRules, AnonymousTypeDescr static bool hasDefaultScope(bool useUpdatedEscapeRules, AnonymousTypeField field) { + if (field.HasUnscopedRefAttribute) + { + return false; + } return (field.Scope, ParameterHelpers.IsRefScopedByDefault(useUpdatedEscapeRules, field.RefKind)) switch { - (DeclarationScope.Unscoped, false) => true, - (DeclarationScope.RefScoped, true) => true, + (ScopedKind.None, false) => true, + (ScopedKind.ScopedRef, true) => true, _ => false }; } @@ -450,7 +454,7 @@ private NamedTypeSymbol ConstructAnonymousTypeImplementationSymbol(AnonymousType private AnonymousTypeTemplateSymbol CreatePlaceholderTemplate(Microsoft.CodeAnalysis.Emit.AnonymousTypeKey key) { - var fields = key.Fields.SelectAsArray(f => new AnonymousTypeField(f.Name, Location.None, typeWithAnnotations: default, refKind: RefKind.None, DeclarationScope.Unscoped)); + var fields = key.Fields.SelectAsArray(f => new AnonymousTypeField(f.Name, Location.None, typeWithAnnotations: default, refKind: RefKind.None, ScopedKind.None)); var typeDescr = new AnonymousTypeDescriptor(fields, Location.None); return new AnonymousTypeTemplateSymbol(this, typeDescr); } diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/PublicSymbols/AnonymousType.DelegatePublicSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/PublicSymbols/AnonymousType.DelegatePublicSymbol.cs index a24ba1a9c069d..3f1246a22190f 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/PublicSymbols/AnonymousType.DelegatePublicSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/PublicSymbols/AnonymousType.DelegatePublicSymbol.cs @@ -54,11 +54,12 @@ private ImmutableArray CreateMembers() var constructor = new SynthesizedDelegateConstructor(this, Manager.System_Object, Manager.System_IntPtr); var fields = TypeDescriptor.Fields; int parameterCount = fields.Length - 1; - var parameters = ArrayBuilder<(TypeWithAnnotations, RefKind, DeclarationScope, ConstantValue?, bool)>.GetInstance(parameterCount); + var parameters = ArrayBuilder.GetInstance(parameterCount); for (int i = 0; i < parameterCount; i++) { var field = fields[i]; - parameters.Add((field.TypeWithAnnotations, field.RefKind, field.Scope, field.DefaultValue, field.IsParams)); + parameters.Add( + new SynthesizedDelegateInvokeMethod.ParameterDescription(field.TypeWithAnnotations, field.RefKind, field.Scope, field.DefaultValue, isParams: field.IsParams, hasUnscopedRefAttribute: field.HasUnscopedRefAttribute)); } var returnField = fields.Last(); var invokeMethod = new SynthesizedDelegateInvokeMethod(this, parameters, returnField.TypeWithAnnotations, returnField.RefKind); 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 d9f30fb7998b1..f618218d597ca 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.DelegateTemplateSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.DelegateTemplateSymbol.cs @@ -53,10 +53,11 @@ static SynthesizedDelegateInvokeMethod createInvokeMethod(AnonymousDelegateTempl var typeParams = containingType.TypeParameters; int parameterCount = typeParams.Length - (voidReturnTypeOpt is null ? 1 : 0); - var parameters = ArrayBuilder<(TypeWithAnnotations Type, RefKind RefKind, DeclarationScope Scope, ConstantValue? DefaultValue, bool IsParams)>.GetInstance(parameterCount); + var parameters = ArrayBuilder.GetInstance(parameterCount); for (int i = 0; i < parameterCount; i++) { - parameters.Add((TypeWithAnnotations.Create(typeParams[i]), refKinds.IsNull ? RefKind.None : refKinds[i], DeclarationScope.Unscoped, DefaultValue: null, IsParams: false)); + parameters.Add( + new SynthesizedDelegateInvokeMethod.ParameterDescription(TypeWithAnnotations.Create(typeParams[i]), refKinds.IsNull ? RefKind.None : refKinds[i], ScopedKind.None, defaultValue: null, isParams: false, hasUnscopedRefAttribute: false)); } // if we are given Void type the method returns Void, otherwise its return type is the last type parameter of the delegate: @@ -118,7 +119,7 @@ static SynthesizedDelegateInvokeMethod createInvokeMethod( var returnsVoid = returnParameter.Type.IsVoidType(); var parameterCount = fields.Length - 1; - var parameters = ArrayBuilder<(TypeWithAnnotations Type, RefKind RefKind, DeclarationScope Scope, ConstantValue? DefaultValue, bool IsParams)>.GetInstance(parameterCount); + var parameters = ArrayBuilder.GetInstance(parameterCount); for (int i = 0; i < parameterCount; i++) { var field = fields[i]; @@ -130,7 +131,8 @@ static SynthesizedDelegateInvokeMethod createInvokeMethod( type = TypeWithAnnotations.Create(ArrayTypeSymbol.CreateSZArray(containingType.ContainingAssembly, type)); } - parameters.Add((type, field.RefKind, field.Scope, field.DefaultValue, field.IsParams)); + parameters.Add( + new SynthesizedDelegateInvokeMethod.ParameterDescription(type, field.RefKind, field.Scope, field.DefaultValue, isParams: field.IsParams, hasUnscopedRefAttribute: field.HasUnscopedRefAttribute)); } // if we are given Void type the method returns Void, otherwise its return type is the last type parameter of the delegate @@ -185,11 +187,12 @@ static SynthesizedDelegateInvokeMethod createInvokeMethod( TypeMap typeMap) { var parameterCount = fields.Length - 1; - var parameters = ArrayBuilder<(TypeWithAnnotations, RefKind, DeclarationScope, ConstantValue?, bool)>.GetInstance(parameterCount); + var parameters = ArrayBuilder.GetInstance(parameterCount); for (int i = 0; i < parameterCount; i++) { var field = fields[i]; - parameters.Add((typeMap.SubstituteType(field.Type), field.RefKind, field.Scope, field.DefaultValue, field.IsParams)); + parameters.Add( + new SynthesizedDelegateInvokeMethod.ParameterDescription(typeMap.SubstituteType(field.Type), field.RefKind, field.Scope, field.DefaultValue, isParams: field.IsParams, hasUnscopedRefAttribute: field.HasUnscopedRefAttribute)); } var returnParameter = fields[^1]; diff --git a/src/Compilers/CSharp/Portable/Symbols/Compilation_WellKnownMembers.cs b/src/Compilers/CSharp/Portable/Symbols/Compilation_WellKnownMembers.cs index b7b69d698c79b..d7304cff1db1f 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Compilation_WellKnownMembers.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Compilation_WellKnownMembers.cs @@ -472,6 +472,15 @@ internal override ITypeSymbolInternal CommonGetWellKnownType(WellKnownType wellk )); } + internal SynthesizedAttributeData? SynthesizeDateTimeConstantAttribute(DateTime value) + { + var ticks = new TypedConstant(GetSpecialType(SpecialType.System_Int64), TypedConstantKind.Primitive, value.Ticks); + + return TrySynthesizeAttribute( + WellKnownMember.System_Runtime_CompilerServices_DateTimeConstantAttribute__ctor, + ImmutableArray.Create(ticks)); + } + internal SynthesizedAttributeData? SynthesizeDebuggerBrowsableNeverAttribute() { if (Options.OptimizationLevel != OptimizationLevel.Debug) diff --git a/src/Compilers/CSharp/Portable/Symbols/ConstantValueUtils.cs b/src/Compilers/CSharp/Portable/Symbols/ConstantValueUtils.cs index f2315cb95a777..4f9b41def3ff0 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ConstantValueUtils.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ConstantValueUtils.cs @@ -104,9 +104,9 @@ internal static ConstantValue GetAndValidateConstantValue( // If we have already computed the unconverted constant value, then this call is cheap // because BoundConversions store their constant values (i.e. not recomputing anything). - var constantValue = boundValue.ConstantValue; + var constantValue = boundValue.ConstantValueOpt; - var unconvertedConstantValue = unconvertedBoundValue.ConstantValue; + var unconvertedConstantValue = unconvertedBoundValue.ConstantValueOpt; if (unconvertedConstantValue != null && !unconvertedConstantValue.IsNull && typeSymbol.IsReferenceType && diff --git a/src/Compilers/CSharp/Portable/Symbols/DeclarationScope.cs b/src/Compilers/CSharp/Portable/Symbols/DeclarationScope.cs deleted file mode 100644 index dd3b8db748a81..0000000000000 --- a/src/Compilers/CSharp/Portable/Symbols/DeclarationScope.cs +++ /dev/null @@ -1,29 +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 Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.CSharp.Symbols -{ - internal enum DeclarationScope : byte - { - Unscoped = 0, - RefScoped = 1, - ValueScoped = 2, - } - - internal static class DeclarationScopeExtensions - { - internal static ScopedKind AsScopedKind(this DeclarationScope scope) - { - return scope switch - { - DeclarationScope.Unscoped => ScopedKind.None, - DeclarationScope.RefScoped => ScopedKind.ScopedRef, - DeclarationScope.ValueScoped => ScopedKind.ScopedValue, - _ => throw ExceptionUtilities.UnexpectedValue(scope), - }; - } - } -} diff --git a/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerParameterSymbol.cs index a31b0d269645d..46ab793940098 100644 --- a/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerParameterSymbol.cs @@ -29,8 +29,8 @@ public FunctionPointerParameterSymbol(TypeWithAnnotations typeWithAnnotations, R public override Symbol ContainingSymbol => _containingSymbol; public override ImmutableArray RefCustomModifiers { get; } - internal override DeclarationScope EffectiveScope - => ParameterHelpers.IsRefScopedByDefault(this) ? DeclarationScope.RefScoped : DeclarationScope.Unscoped; + internal override ScopedKind EffectiveScope + => ParameterHelpers.IsRefScopedByDefault(this) ? ScopedKind.ScopedRef : ScopedKind.None; internal override bool HasUnscopedRefAttribute => false; internal override bool UseUpdatedEscapeRules => _containingSymbol.UseUpdatedEscapeRules; diff --git a/src/Compilers/CSharp/Portable/Symbols/LocalSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/LocalSymbol.cs index 0c19932d63b6b..6b245b6162c3b 100644 --- a/src/Compilers/CSharp/Portable/Symbols/LocalSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/LocalSymbol.cs @@ -6,6 +6,7 @@ using System.Collections.Immutable; using System.Diagnostics; +using System.Runtime.CompilerServices; using Microsoft.CodeAnalysis.CodeGen; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Symbols; @@ -37,7 +38,14 @@ internal abstract SynthesizedLocalKind SynthesizedKind /// internal abstract SyntaxNode ScopeDesignatorOpt { get; } - internal abstract LocalSymbol WithSynthesizedLocalKindAndSyntax(SynthesizedLocalKind kind, SyntaxNode syntax); + internal abstract LocalSymbol WithSynthesizedLocalKindAndSyntax( + SynthesizedLocalKind kind, SyntaxNode syntax +#if DEBUG + , + [CallerLineNumber] int createdAtLineNumber = 0, + [CallerFilePath] string createdAtFilePath = null +#endif + ); internal abstract bool IsImportedFromMetadata { @@ -186,7 +194,7 @@ public sealed override SymbolKind Kind } } - internal abstract DeclarationScope Scope { get; } + internal abstract ScopedKind Scope { get; } internal sealed override TResult Accept(CSharpSymbolVisitor visitor, TArgument argument) { @@ -354,18 +362,6 @@ public abstract RefKind RefKind get; } - /// - /// Returns the scope to which a local can "escape" ref assignments or other form of aliasing - /// Makes sense only for locals with formal scopes - i.e. source locals - /// - internal abstract uint RefEscapeScope { get; } - - /// - /// Returns the scope to which values of a local can "escape" via ordinary assignments - /// Makes sense only for ref-like locals with formal scopes - i.e. source locals - /// - internal abstract uint ValEscapeScope { get; } - /// /// When a local variable's type is inferred, it may not be used in the /// expression that computes its value (and type). This property returns diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEParameterSymbol.cs index ecd15862378dc..d6fe6ae2cd9b9 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEParameterSymbol.cs @@ -80,9 +80,9 @@ public bool HasNameInMetadata get { return (_bits & HasNameInMetadataBit) != 0; } } - public DeclarationScope Scope + public ScopedKind Scope { - get { return (DeclarationScope)((_bits >> ScopeOffset) & ScopeMask); } + get { return (ScopedKind)((_bits >> ScopeOffset) & ScopeMask); } } public bool HasUnscopedRefAttribute @@ -97,11 +97,11 @@ static PackedFlags() Debug.Assert(EnumUtilities.ContainsAllValues(WellKnownAttributeDataMask)); Debug.Assert(EnumUtilities.ContainsAllValues(RefKindMask)); Debug.Assert(EnumUtilities.ContainsAllValues(FlowAnalysisAnnotationsMask)); - Debug.Assert(EnumUtilities.ContainsAllValues(ScopeMask)); + Debug.Assert(EnumUtilities.ContainsAllValues(ScopeMask)); } #endif - public PackedFlags(RefKind refKind, bool attributesAreComplete, bool hasNameInMetadata, DeclarationScope scope, bool hasUnscopedRefAttribute) + public PackedFlags(RefKind refKind, bool attributesAreComplete, bool hasNameInMetadata, ScopedKind scope, bool hasUnscopedRefAttribute) { int refKindBits = ((int)refKind & RefKindMask) << RefKindOffset; int attributeBits = attributesAreComplete ? AllWellKnownAttributesCompleteNoData : 0; @@ -245,7 +245,7 @@ private PEParameterSymbol( _handle = handle; RefKind refKind = RefKind.None; - DeclarationScope scope = DeclarationScope.Unscoped; + ScopedKind scope = ScopedKind.None; bool hasUnscopedRefAttribute = false; if (handle.IsNil) @@ -309,18 +309,18 @@ private PEParameterSymbol( { isBad = true; } - scope = DeclarationScope.Unscoped; + scope = ScopedKind.None; } else if (_moduleSymbol.Module.HasScopedRefAttribute(_handle)) { if (isByRef) { Debug.Assert(refKind != RefKind.None); - scope = DeclarationScope.RefScoped; + scope = ScopedKind.ScopedRef; } else if (typeWithAnnotations.Type.IsRefLikeType) { - scope = DeclarationScope.ValueScoped; + scope = ScopedKind.ScopedValue; } else { @@ -329,7 +329,7 @@ private PEParameterSymbol( } else if (ParameterHelpers.IsRefScopedByDefault(_moduleSymbol.UseUpdatedEscapeRules, refKind)) { - scope = DeclarationScope.RefScoped; + scope = ScopedKind.ScopedRef; } } @@ -1003,7 +1003,7 @@ public override ImmutableArray DeclaringSyntaxReferences } } - internal sealed override DeclarationScope EffectiveScope => _packedFlags.Scope; + internal sealed override ScopedKind EffectiveScope => _packedFlags.Scope; internal override bool HasUnscopedRefAttribute => _packedFlags.HasUnscopedRefAttribute; diff --git a/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs index 413a9e308c56c..5f85462fcdeb1 100644 --- a/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs @@ -4,15 +4,10 @@ #nullable disable -using Microsoft.CodeAnalysis.Collections; -using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; -using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using Microsoft.CodeAnalysis.CSharp.Syntax; -using System.Linq; -using System.Diagnostics.CodeAnalysis; namespace Microsoft.CodeAnalysis.CSharp.Symbols { @@ -222,8 +217,18 @@ internal static bool IsValidUnscopedRefAttributeTarget(this MethodSymbol method) { return !method.IsStatic && method.ContainingType?.IsStructType() == true && - !method.IsConstructor() && + method.MethodKind is (MethodKind.Ordinary or MethodKind.ExplicitInterfaceImplementation or MethodKind.PropertyGet or MethodKind.PropertySet) && !method.IsInitOnly; } + + internal static bool HasUnscopedRefAttributeOnMethodOrProperty(this MethodSymbol? method) + { + if (method is null) + { + return false; + } + return method.HasUnscopedRefAttribute || + method.AssociatedSymbol is PropertySymbol { HasUnscopedRefAttribute: true }; + } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/ParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/ParameterSymbol.cs index f86975fd89790..9a8bc63dfdff8 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ParameterSymbol.cs @@ -414,7 +414,7 @@ internal sealed override ObsoleteAttributeData? ObsoleteAttributeData /// The effective scope. This is from the declared scope, implicit scope and any /// UnscopedRefAttribute. /// - internal abstract DeclarationScope EffectiveScope { get; } + internal abstract ScopedKind EffectiveScope { get; } internal abstract bool HasUnscopedRefAttribute { get; } diff --git a/src/Compilers/CSharp/Portable/Symbols/PublicModel/LocalSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PublicModel/LocalSymbol.cs index efd106f4fb90f..b03e227df51a8 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PublicModel/LocalSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PublicModel/LocalSymbol.cs @@ -51,7 +51,7 @@ bool ILocalSymbol.IsFunctionValue RefKind ILocalSymbol.RefKind => _underlying.RefKind; - ScopedKind ILocalSymbol.ScopedKind => _underlying.Scope.AsScopedKind(); + ScopedKind ILocalSymbol.ScopedKind => _underlying.Scope; bool ILocalSymbol.HasConstantValue => _underlying.HasConstantValue; diff --git a/src/Compilers/CSharp/Portable/Symbols/PublicModel/ParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PublicModel/ParameterSymbol.cs index 0e2adc20699bb..afa97d38862fa 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PublicModel/ParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PublicModel/ParameterSymbol.cs @@ -58,7 +58,7 @@ IParameterSymbol IParameterSymbol.OriginalDefinition RefKind IParameterSymbol.RefKind => _underlying.RefKind; - ScopedKind IParameterSymbol.ScopedKind => _underlying.EffectiveScope.AsScopedKind(); + ScopedKind IParameterSymbol.ScopedKind => _underlying.EffectiveScope; bool IParameterSymbol.IsDiscard => _underlying.IsDiscard; diff --git a/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyParameterSymbol.cs index 73fbe2cbff6bb..0c9895980007e 100644 --- a/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyParameterSymbol.cs @@ -48,8 +48,8 @@ public SignatureOnlyParameterSymbol( public override bool IsDiscard { get { return false; } } - internal override DeclarationScope EffectiveScope - => ParameterHelpers.IsRefScopedByDefault(this) ? DeclarationScope.RefScoped : DeclarationScope.Unscoped; + internal override ScopedKind EffectiveScope + => ParameterHelpers.IsRefScopedByDefault(this) ? ScopedKind.ScopedRef : ScopedKind.None; internal override bool HasUnscopedRefAttribute => false; diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/LambdaParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/LambdaParameterSymbol.cs index 7a9f05f4d30d2..851189250bb74 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/LambdaParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/LambdaParameterSymbol.cs @@ -19,7 +19,7 @@ public LambdaParameterSymbol( TypeWithAnnotations parameterType, int ordinal, RefKind refKind, - DeclarationScope scope, + ScopedKind scope, string name, bool isDiscard, bool isParams, diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs index 75fa9393606b8..33c66058c9150 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs @@ -336,7 +336,7 @@ private ImmutableArray MakeParameters( TypeWithAnnotations type; RefKind refKind; - DeclarationScope scope; + ScopedKind scope; ParameterSyntax? paramSyntax = null; if (hasExplicitlyTypedParameterList) { @@ -349,13 +349,13 @@ private ImmutableArray MakeParameters( { type = parameterTypes[p]; refKind = RefKind.None; - scope = DeclarationScope.Unscoped; + scope = ScopedKind.None; } else { type = TypeWithAnnotations.Create(new ExtendedErrorTypeSymbol(compilation, name: string.Empty, arity: 0, errorInfo: null)); refKind = RefKind.None; - scope = DeclarationScope.Unscoped; + scope = ScopedKind.None; } var attributeLists = unboundLambda.ParameterAttributes(p); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs b/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs index f3d2a952a1476..4c90e7e60b40e 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs @@ -40,7 +40,7 @@ public static ImmutableArray MakeParameters( parameterCreationFunc: (Binder context, Symbol owner, TypeWithAnnotations parameterType, ParameterSyntax syntax, RefKind refKind, int ordinal, SyntaxToken paramsKeyword, SyntaxToken thisKeyword, bool addRefReadOnlyModifier, - DeclarationScope scope, + ScopedKind scope, BindingDiagnosticBag declarationDiagnostics) => { return SourceParameterSymbol.Create( @@ -80,7 +80,7 @@ public static ImmutableArray MakeFunctionPointer parameterCreationFunc: (Binder binder, FunctionPointerMethodSymbol owner, TypeWithAnnotations parameterType, FunctionPointerParameterSyntax syntax, RefKind refKind, int ordinal, SyntaxToken paramsKeyword, SyntaxToken thisKeyword, bool addRefReadOnlyModifier, - DeclarationScope scope, + ScopedKind scope, BindingDiagnosticBag diagnostics) => { // Non-function pointer locations have other locations to encode in/ref readonly/outness. For function pointers, @@ -119,7 +119,7 @@ private static ImmutableArray MakeParameters parameterCreationFunc, + Func parameterCreationFunc, bool parsingFunctionPointer = false) where TParameterSyntax : BaseParameterSyntax where TParameterSymbol : ParameterSymbol @@ -139,7 +139,7 @@ private static ImmutableArray MakeParameters MakeParameters _originalParam.EffectiveScope; + internal sealed override ScopedKind EffectiveScope => _originalParam.EffectiveScope; internal override bool HasUnscopedRefAttribute => _originalParam.HasUnscopedRefAttribute; diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs index 883c0501784fd..4030ccf03b3cc 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs @@ -46,7 +46,7 @@ protected SourceComplexParameterSymbolBase( SyntaxReference syntaxRef, bool isParams, bool isExtensionMethodThis, - DeclarationScope scope) + ScopedKind scope) : base(owner, parameterType, ordinal, refKind, scope, name, locations) { Debug.Assert((syntaxRef == null) || (syntaxRef.GetSyntax().IsKind(SyntaxKind.Parameter))); @@ -198,15 +198,15 @@ internal bool HasEnumeratorCancellationAttribute #nullable enable - internal sealed override DeclarationScope EffectiveScope + internal sealed override ScopedKind EffectiveScope { get { var scope = CalculateEffectiveScopeIgnoringAttributes(); - if (scope != DeclarationScope.Unscoped && + if (scope != ScopedKind.None && HasUnscopedRefAttribute) { - return DeclarationScope.Unscoped; + return ScopedKind.None; } return scope; } @@ -259,6 +259,16 @@ private ConstantValue DefaultSyntaxValue if (!_lazyDefaultSyntaxValue.IsBad) { VerifyParamDefaultValueMatchesAttributeIfAny(_lazyDefaultSyntaxValue, parameterEqualsValue.Value.Syntax, diagnostics); + + // Ensure availability of `DecimalConstantAttribute`. + if (_lazyDefaultSyntaxValue.IsDecimal && + DefaultValueFromAttributes == ConstantValue.NotAvailable) + { + Binder.ReportUseSiteDiagnosticForSynthesizedAttribute(DeclaringCompilation, + WellKnownMember.System_Runtime_CompilerServices_DecimalConstantAttribute__ctor, + diagnostics, + parameterEqualsValue.Value.Syntax.Location); + } } } @@ -380,7 +390,7 @@ private ConstantValue MakeDefaultExpression(BindingDiagnosticBag diagnostics, ou // If we have something like M(double? x = 1) then the expression we'll get is (double?)1, which // does not have a constant value. The constant value we want is (double)1. // The default literal conversion is an exception: (double)default would give the wrong value for M(double? x = default). - if (convertedExpression.ConstantValue == null && convertedExpression.Kind == BoundKind.Conversion && + if (convertedExpression.ConstantValueOpt == null && convertedExpression.Kind == BoundKind.Conversion && ((BoundConversion)convertedExpression).ConversionKind != ConversionKind.DefaultLiteral) { if (parameterType.Type.IsNullableType()) @@ -391,7 +401,7 @@ private ConstantValue MakeDefaultExpression(BindingDiagnosticBag diagnostics, ou } // represent default(struct) by a Null constant: - var value = convertedExpression.ConstantValue ?? ConstantValue.Null; + var value = convertedExpression.ConstantValueOpt ?? ConstantValue.Null; return value; } @@ -847,7 +857,7 @@ protected override void DecodeWellKnownAttributeImpl(ref DecodeWellKnownAttribut { diagnostics.Add(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, arguments.AttributeSyntaxOpt.Location); } - else if (DeclaredScope != DeclarationScope.Unscoped) + else if (DeclaredScope != ScopedKind.None) { diagnostics.Add(ErrorCode.ERR_UnscopedScoped, arguments.AttributeSyntaxOpt.Location); } @@ -1504,7 +1514,7 @@ internal SourceComplexParameterSymbol( SyntaxReference syntaxRef, bool isParams, bool isExtensionMethodThis, - DeclarationScope scope) + ScopedKind scope) : base(owner, ordinal, parameterType, refKind, name, locations, syntaxRef, isParams, isExtensionMethodThis, scope) { } @@ -1527,7 +1537,7 @@ internal SourceComplexParameterSymbolWithCustomModifiersPrecedingRef( SyntaxReference syntaxRef, bool isParams, bool isExtensionMethodThis, - DeclarationScope scope) + ScopedKind scope) : base(owner, ordinal, parameterType, refKind, name, locations, syntaxRef, isParams, isExtensionMethodThis, scope) { Debug.Assert(!refCustomModifiers.IsEmpty); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventSymbol.cs index cf6fe3402459c..57b8d958ebe36 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventSymbol.cs @@ -307,6 +307,10 @@ protected sealed override void DecodeWellKnownAttributeImpl(ref DecodeWellKnownA { CSharpAttributeData.DecodeSkipLocalsInitAttribute(DeclaringCompilation, ref arguments); } + else if (attribute.IsTargetAttribute(this, AttributeDescription.UnscopedRefAttribute)) + { + diagnostics.Add(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, arguments.AttributeSyntaxOpt!.Location); + } } internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder? attributes) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceLocalSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceLocalSymbol.cs index 03078c7b27815..ccbacc8bf13bd 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceLocalSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceLocalSymbol.cs @@ -8,6 +8,7 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Linq; +using System.Runtime.CompilerServices; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; using Roslyn.Utilities; @@ -31,22 +32,10 @@ internal class SourceLocalSymbol : LocalSymbol private readonly TypeSyntax _typeSyntax; private readonly RefKind _refKind; private readonly LocalDeclarationKind _declarationKind; - private readonly DeclarationScope _scope; + private readonly ScopedKind _scope; private TypeWithAnnotations.Boxed _type; - /// - /// Scope to which the local can "escape" via aliasing/ref assignment. - /// Not readonly because we can only know escape values after binding the initializer. - /// - protected uint _refEscapeScope; - - /// - /// Scope to which the local's values can "escape" via ordinary assignments. - /// Not readonly because we can only know escape values after binding the initializer. - /// - protected uint _valEscapeScope; - private SourceLocalSymbol( Symbol containingSymbol, Binder scopeBinder, @@ -76,21 +65,13 @@ private SourceLocalSymbol( typeSyntax.SkipRefInLocalOrReturn(diagnostics: null, out _refKind); _scope = _refKind != RefKind.None - ? isScoped ? DeclarationScope.RefScoped : DeclarationScope.Unscoped - : isScoped ? DeclarationScope.ValueScoped : DeclarationScope.Unscoped; + ? isScoped ? ScopedKind.ScopedRef : ScopedKind.None + : isScoped ? ScopedKind.ScopedValue : ScopedKind.None; this._declarationKind = declarationKind; // create this eagerly as it will always be needed for the EnsureSingleDefinition _locations = ImmutableArray.Create(identifierToken.GetLocation()); - - _refEscapeScope = this._refKind == RefKind.None ? - scopeBinder.LocalScopeDepth : - Binder.CallingMethodScope; // default to returnable, unless there is initializer - - // we do not know the type yet. - // assume this is returnable in case we never get to know our type. - _valEscapeScope = Binder.CallingMethodScope; } /// @@ -106,46 +87,7 @@ internal override SyntaxNode ScopeDesignatorOpt get { return _scopeBinder.ScopeDesignator; } } - // From https://github.com/dotnet/csharplang/blob/main/csharp-11.0/proposals/low-level-struct-improvements.md: - // - // | Parameter or Local | ref-safe-to-escape | safe-to-escape | - // |------------------------|--------------------|----------------| - // | Span s | current method | calling method | - // | scoped Span s | current method | current method | - // | ref Span s | calling method | calling method | - // | scoped ref Span s | current method | calling method | - - internal sealed override uint RefEscapeScope - { - get - { - if (!_scopeBinder.UseUpdatedEscapeRules || - _scope == DeclarationScope.Unscoped) - { - return _refEscapeScope; - } - return _scope == DeclarationScope.RefScoped ? - _scopeBinder.LocalScopeDepth : - Binder.CurrentMethodScope; - } - } - - internal sealed override uint ValEscapeScope - { - get - { - if (!_scopeBinder.UseUpdatedEscapeRules || - _scope == DeclarationScope.Unscoped) - { - return _valEscapeScope; - } - return _scope == DeclarationScope.ValueScoped ? - _scopeBinder.LocalScopeDepth : - Binder.CallingMethodScope; - } - } - - internal sealed override DeclarationScope Scope => _scope; + internal sealed override ScopedKind Scope => _scope; /// /// Binder that should be used to bind type syntax for the local. @@ -288,7 +230,14 @@ internal override SynthesizedLocalKind SynthesizedKind get { return SynthesizedLocalKind.UserDefined; } } - internal override LocalSymbol WithSynthesizedLocalKindAndSyntax(SynthesizedLocalKind kind, SyntaxNode syntax) + internal override LocalSymbol WithSynthesizedLocalKindAndSyntax( + SynthesizedLocalKind kind, SyntaxNode syntax +#if DEBUG + , + [CallerLineNumber] int createdAtLineNumber = 0, + [CallerFilePath] string createdAtFilePath = null +#endif + ) { throw ExceptionUtilities.Unreachable(); } @@ -308,21 +257,6 @@ internal sealed override bool IsKnownToReferToTempIfReferenceType get { return false; } } - internal virtual void SetRefEscape(uint value) - { - _refEscapeScope = value; - } - - internal virtual void SetValEscape(uint value) - { - // either we should be setting the val escape for the first time, - // or not contradicting what was set before. - Debug.Assert( - _valEscapeScope == Binder.CallingMethodScope - || _valEscapeScope == value); - _valEscapeScope = value; - } - public override Symbol ContainingSymbol { get { return _containingSymbol; } @@ -604,10 +538,6 @@ public LocalWithInitializer( _initializer = initializer; _initializerBinder = initializerBinder; - - // default to the current scope in case we need to handle self-referential error cases. - _refEscapeScope = _scopeBinder.LocalScopeDepth; - _valEscapeScope = _scopeBinder.LocalScopeDepth; } protected override TypeWithAnnotations InferTypeOfVarVariable(BindingDiagnosticBag diagnostics) @@ -666,20 +596,6 @@ internal override ImmutableBindingDiagnostic GetConstantValueDia MakeConstantTuple(inProgress: null, boundInitValue: boundInitValue); return _constantTuple == null ? ImmutableBindingDiagnostic.Empty : _constantTuple.Diagnostics; } - - internal override void SetRefEscape(uint value) - { - Debug.Assert(!_scopeBinder.UseUpdatedEscapeRules || _scope == DeclarationScope.Unscoped); - Debug.Assert(value <= _refEscapeScope); - _refEscapeScope = value; - } - - internal override void SetValEscape(uint value) - { - Debug.Assert(!_scopeBinder.UseUpdatedEscapeRules || _scope == DeclarationScope.Unscoped); - Debug.Assert(value <= _valEscapeScope); - _valEscapeScope = value; - } } /// @@ -725,7 +641,7 @@ protected override TypeWithAnnotations InferTypeOfVarVariable(BindingDiagnosticB /// Symbol for a deconstruction local that might require type inference. /// For instance, local x in var (x, y) = ... or (var x, int y) = .... /// - private class DeconstructionLocalSymbol : SourceLocalSymbol + private sealed class DeconstructionLocalSymbol : SourceLocalSymbol { private readonly SyntaxNode _deconstruction; private readonly Binder _nodeBinder; @@ -788,7 +704,7 @@ internal override SyntaxNode ForbiddenZone } } - private class LocalSymbolWithEnclosingContext : SourceLocalSymbol + private sealed class LocalSymbolWithEnclosingContext : SourceLocalSymbol { private readonly SyntaxNode _forbiddenZone; private readonly Binder _nodeBinder; diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs index 6f57b9965448b..3cc784c8ee3ba 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs @@ -832,6 +832,8 @@ internal override ManagedKind GetManagedKind(ref CompoundUseSiteInfo HasFlag(DeclarationModifiers.File); + internal bool IsUnsafe => HasFlag(DeclarationModifiers.Unsafe); + internal SyntaxTree AssociatedSyntaxTree => declaration.Declarations[0].Location.SourceTree; internal sealed override FileIdentifier? AssociatedFileIdentifier diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol_ImplementationChecks.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol_ImplementationChecks.cs index 1463243c9f3db..82e1b08e9f15a 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol_ImplementationChecks.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol_ImplementationChecks.cs @@ -1466,9 +1466,9 @@ internal static bool CheckValidScopedOverride( static bool isValidScopedConversion( bool allowVariance, - DeclarationScope baseScope, + ScopedKind baseScope, bool baseHasUnscopedRefAttribute, - DeclarationScope overrideScope, + ScopedKind overrideScope, bool overrideHasUnscopedRefAttribute) { if (baseScope == overrideScope) @@ -1479,7 +1479,7 @@ static bool isValidScopedConversion( } return allowVariance && !overrideHasUnscopedRefAttribute; } - return allowVariance && baseScope == DeclarationScope.Unscoped; + return allowVariance && baseScope == ScopedKind.None; } } #nullable disable diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs index 49d814ec38d7e..bf46d60ea5ad7 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs @@ -128,6 +128,22 @@ internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, r } } + internal override void PostDecodeWellKnownAttributes(ImmutableArray boundAttributes, ImmutableArray allAttributeSyntaxNodes, BindingDiagnosticBag diagnostics, AttributeLocation symbolPart, WellKnownAttributeData decodedData) + { + base.PostDecodeWellKnownAttributes(boundAttributes, allAttributeSyntaxNodes, diagnostics, symbolPart, decodedData); + + // Ensure availability of `DecimalConstantAttribute`. + if (IsConst && Type.SpecialType == SpecialType.System_Decimal && + GetConstantValue(ConstantFieldsInProgress.Empty, earlyDecodingWellKnownAttributes: false) is { } value && + !(decodedData is FieldWellKnownAttributeData fieldData && fieldData.ConstValue != CodeAnalysis.ConstantValue.Unset)) + { + Binder.ReportUseSiteDiagnosticForSynthesizedAttribute(DeclaringCompilation, + WellKnownMember.System_Runtime_CompilerServices_DecimalConstantAttribute__ctor, + diagnostics, + syntax: SyntaxNode); + } + } + public override Symbol AssociatedSymbol { get diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs index 8da4b2155ccda..01864120d85ea 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs @@ -588,7 +588,7 @@ private void DecodeWellKnownAttributeAppliedToMethod(ref DecodeWellKnownAttribut } else { - diagnostics.Add(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, arguments.AttributeSyntaxOpt.Location); + diagnostics.Add(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, arguments.AttributeSyntaxOpt.Location); } } else diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceParameterSymbol.cs index d91e89468575b..c889c41731fbb 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceParameterSymbol.cs @@ -25,7 +25,7 @@ internal abstract class SourceParameterSymbol : SourceParameterSymbolBase private readonly string _name; private readonly ImmutableArray _locations; private readonly RefKind _refKind; - private readonly DeclarationScope _scope; + private readonly ScopedKind _scope; public static SourceParameterSymbol Create( Binder context, @@ -38,7 +38,7 @@ public static SourceParameterSymbol Create( bool isParams, bool isExtensionMethodThis, bool addRefReadOnlyModifier, - DeclarationScope scope, + ScopedKind scope, BindingDiagnosticBag declarationDiagnostics) { Debug.Assert(!(owner is LambdaSymbol)); // therefore we don't need to deal with discard parameters @@ -101,7 +101,7 @@ protected SourceParameterSymbol( TypeWithAnnotations parameterType, int ordinal, RefKind refKind, - DeclarationScope scope, + ScopedKind scope, string name, ImmutableArray locations) : base(owner, ordinal) @@ -225,15 +225,15 @@ public sealed override RefKind RefKind /// /// The declared scope. From source, this is from the scope keyword only. /// - internal DeclarationScope DeclaredScope => _scope; + internal ScopedKind DeclaredScope => _scope; - internal abstract override DeclarationScope EffectiveScope { get; } + internal abstract override ScopedKind EffectiveScope { get; } - protected DeclarationScope CalculateEffectiveScopeIgnoringAttributes() + protected ScopedKind CalculateEffectiveScopeIgnoringAttributes() { var declaredScope = this.DeclaredScope; - return declaredScope == DeclarationScope.Unscoped && ParameterHelpers.IsRefScopedByDefault(this) ? - DeclarationScope.RefScoped : + return declaredScope == ScopedKind.None && ParameterHelpers.IsRefScopedByDefault(this) ? + ScopedKind.ScopedRef : declaredScope; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs index f6398f0ece2f8..8065866324b81 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs @@ -1321,7 +1321,7 @@ protected override void DecodeWellKnownAttributeImpl(ref DecodeWellKnownAttribut } else { - diagnostics.Add(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, arguments.AttributeSyntaxOpt.Location); + diagnostics.Add(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, arguments.AttributeSyntaxOpt.Location); } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceSimpleParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceSimpleParameterSymbol.cs index c7777acfd2105..362ceb65ebb0b 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceSimpleParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceSimpleParameterSymbol.cs @@ -18,7 +18,7 @@ public SourceSimpleParameterSymbol( TypeWithAnnotations parameterType, int ordinal, RefKind refKind, - DeclarationScope scope, + ScopedKind scope, string name, ImmutableArray locations) : base(owner, parameterType, ordinal, refKind, scope, name, locations) @@ -129,7 +129,7 @@ internal override ConstantValue DefaultValueFromAttributes get { return ConstantValue.NotAvailable; } } - internal override DeclarationScope EffectiveScope => CalculateEffectiveScopeIgnoringAttributes(); + internal override ScopedKind EffectiveScope => CalculateEffectiveScopeIgnoringAttributes(); internal override bool HasUnscopedRefAttribute => false; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/ThisParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/ThisParameterSymbol.cs index d1d9f0e33a4da..4fe1c9c316a02 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/ThisParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/ThisParameterSymbol.cs @@ -166,38 +166,22 @@ internal override MarshalPseudoCustomAttributeData? MarshallingInformation internal override bool HasInterpolatedStringHandlerArgumentError => false; - internal override DeclarationScope EffectiveScope + internal override ScopedKind EffectiveScope { get { - var scope = _containingType.IsStructType() ? DeclarationScope.RefScoped : DeclarationScope.Unscoped; - if (scope != DeclarationScope.Unscoped && + var scope = _containingType.IsStructType() ? ScopedKind.ScopedRef : ScopedKind.None; + if (scope != ScopedKind.None && HasUnscopedRefAttribute) { - return DeclarationScope.Unscoped; + return ScopedKind.None; } return scope; } } internal override bool HasUnscopedRefAttribute - { - get - { - if (_containingMethod is { }) - { - if (_containingMethod.HasUnscopedRefAttribute == true) - { - return true; - } - if (_containingMethod.AssociatedSymbol is PropertySymbol { HasUnscopedRefAttribute: true }) - { - return true; - } - } - return false; - } - } + => _containingMethod.HasUnscopedRefAttributeOnMethodOrProperty(); internal sealed override bool UseUpdatedEscapeRules => _containingMethod?.UseUpdatedEscapeRules ?? _containingType.ContainingModule.UseUpdatedEscapeRules; diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/InterpolatedStringBuilderLocalSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/InterpolatedStringBuilderLocalSymbol.cs deleted file mode 100644 index edd88804af4b0..0000000000000 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/InterpolatedStringBuilderLocalSymbol.cs +++ /dev/null @@ -1,41 +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.Runtime.CompilerServices; -using System.Diagnostics; - -namespace Microsoft.CodeAnalysis.CSharp.Symbols -{ - /// - /// A synthesized local variable with a val escape scope. - /// - [DebuggerDisplay("{GetDebuggerDisplay(),nq}")] - internal sealed class SynthesizedLocalWithValEscape : SynthesizedLocal - { - public SynthesizedLocalWithValEscape( - MethodSymbol? containingMethod, - TypeWithAnnotations typeWithAnnotations, - SynthesizedLocalKind kind, - uint valEscapeScope, - SyntaxNode? syntaxOpt = null, - bool isPinned = false, - RefKind refKind = RefKind.None -#if DEBUG - , - [CallerLineNumber] int createdAtLineNumber = 0, - [CallerFilePath] string? createdAtFilePath = null -#endif - ) : base(containingMethod, typeWithAnnotations, kind, syntaxOpt, isPinned, - isKnownToReferToTempIfReferenceType: false, refKind -#if DEBUG - , createdAtLineNumber, createdAtFilePath -#endif - ) - { - ValEscapeScope = valEscapeScope; - } - - internal override uint ValEscapeScope { get; } - } -} diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordBaseEquals.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordBaseEquals.cs index b58e85af694a1..fd16da02a0fd2 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordBaseEquals.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordBaseEquals.cs @@ -37,7 +37,7 @@ protected override (TypeWithAnnotations ReturnType, ImmutableArray( new SourceSimpleParameterSymbol(owner: this, TypeWithAnnotations.Create(ContainingType.BaseTypeNoUseSiteDiagnostics, NullableAnnotation.Annotated), - ordinal: 0, RefKind.None, DeclarationScope.Unscoped, "other", Locations)), + ordinal: 0, RefKind.None, ScopedKind.None, "other", Locations)), IsVararg: false, DeclaredConstraintsForOverrideOrImplementation: ImmutableArray.Empty); } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordDeconstruct.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordDeconstruct.cs index 30f6d6a18adb3..6610ac14985f0 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordDeconstruct.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordDeconstruct.cs @@ -46,7 +46,7 @@ protected override (TypeWithAnnotations ReturnType, ImmutableArray( new SourceSimpleParameterSymbol(owner: this, TypeWithAnnotations.Create(ContainingType, annotation), - ordinal: 0, RefKind.None, DeclarationScope.Unscoped, "left", Locations), + ordinal: 0, RefKind.None, ScopedKind.None, "left", Locations), new SourceSimpleParameterSymbol(owner: this, TypeWithAnnotations.Create(ContainingType, annotation), - ordinal: 1, RefKind.None, DeclarationScope.Unscoped, "right", Locations))); + ordinal: 1, RefKind.None, ScopedKind.None, "right", Locations))); } protected override int GetParameterCountFromSyntax() => 2; diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEquals.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEquals.cs index bd73dd91103a5..02596a4846bc9 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEquals.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEquals.cs @@ -42,7 +42,7 @@ protected override (TypeWithAnnotations ReturnType, ImmutableArray( new SourceSimpleParameterSymbol(owner: this, TypeWithAnnotations.Create(ContainingType, annotation), - ordinal: 0, RefKind.None, DeclarationScope.Unscoped, "other", Locations)), + ordinal: 0, RefKind.None, ScopedKind.None, "other", Locations)), IsVararg: false, DeclaredConstraintsForOverrideOrImplementation: ImmutableArray.Empty); } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordObjEquals.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordObjEquals.cs index 05ed8b0eb60c9..e3779ce65dc53 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordObjEquals.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordObjEquals.cs @@ -33,7 +33,7 @@ protected override (TypeWithAnnotations ReturnType, ImmutableArray( new SourceSimpleParameterSymbol(owner: this, TypeWithAnnotations.Create(Binder.GetSpecialType(compilation, SpecialType.System_Object, location, diagnostics), annotation), - ordinal: 0, RefKind.None, DeclarationScope.Unscoped, "obj", Locations)), + ordinal: 0, RefKind.None, ScopedKind.None, "obj", Locations)), IsVararg: false, DeclaredConstraintsForOverrideOrImplementation: ImmutableArray.Empty); } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordPrintMembers.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordPrintMembers.cs index 7ed7ac98c4b3e..b0608f0bdf7df 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordPrintMembers.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordPrintMembers.cs @@ -94,7 +94,7 @@ protected override (TypeWithAnnotations ReturnType, ImmutableArray( new SourceSimpleParameterSymbol(owner: this, TypeWithAnnotations.Create(Binder.GetWellKnownType(compilation, WellKnownType.System_Text_StringBuilder, diagnostics, location), annotation), - ordinal: 0, RefKind.None, DeclarationScope.Unscoped, "builder", Locations)), + ordinal: 0, RefKind.None, ScopedKind.None, "builder", Locations)), IsVararg: false, DeclaredConstraintsForOverrideOrImplementation: ImmutableArray.Empty); } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedAccessorValueParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedAccessorValueParameterSymbol.cs index 2a917c29086a1..33b46352b4758 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedAccessorValueParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedAccessorValueParameterSymbol.cs @@ -22,7 +22,7 @@ public SynthesizedAccessorValueParameterSymbol(SourceMemberMethodSymbol accessor syntaxRef: null, isParams: false, isExtensionMethodThis: false, - scope: DeclarationScope.Unscoped) + scope: ScopedKind.None) { } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedDelegateSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedDelegateSymbol.cs index c16d7d3254701..1d51ea39eeb6d 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedDelegateSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedDelegateSymbol.cs @@ -30,14 +30,38 @@ public override ImmutableArray Parameters internal sealed class SynthesizedDelegateInvokeMethod : SynthesizedInstanceMethodSymbol { + internal readonly struct ParameterDescription + { + internal ParameterDescription(TypeWithAnnotations type, RefKind refKind, ScopedKind scope, ConstantValue? defaultValue, bool isParams, bool hasUnscopedRefAttribute) + { + Type = type; + RefKind = refKind; + Scope = scope; + DefaultValue = defaultValue; + IsParams = isParams; + HasUnscopedRefAttribute = hasUnscopedRefAttribute; + } + + internal readonly TypeWithAnnotations Type; + internal readonly RefKind RefKind; + internal readonly ScopedKind Scope; + internal readonly ConstantValue? DefaultValue; + internal readonly bool IsParams; + internal readonly bool HasUnscopedRefAttribute; + } + private readonly NamedTypeSymbol _containingType; - internal SynthesizedDelegateInvokeMethod(NamedTypeSymbol containingType, ArrayBuilder<(TypeWithAnnotations Type, RefKind RefKind, DeclarationScope Scope, ConstantValue? DefaultValue, bool IsParams)> parameterDescriptions, TypeWithAnnotations returnType, RefKind refKind) + internal SynthesizedDelegateInvokeMethod( + NamedTypeSymbol containingType, + ArrayBuilder parameterDescriptions, + TypeWithAnnotations returnType, + RefKind refKind) { _containingType = containingType; Parameters = parameterDescriptions.SelectAsArrayWithIndex(static (p, i, a) => - SynthesizedParameterSymbol.Create(a.Method, p.Type, i, p.RefKind, GeneratedNames.AnonymousDelegateParameterName(i, a.ParameterCount), p.Scope, p.DefaultValue, isParams: p.IsParams), + SynthesizedParameterSymbol.Create(a.Method, p.Type, i, p.RefKind, GeneratedNames.AnonymousDelegateParameterName(i, a.ParameterCount), p.Scope, p.DefaultValue, isParams: p.IsParams, hasUnscopedRefAttribute: p.HasUnscopedRefAttribute), (Method: this, ParameterCount: parameterDescriptions.Count)); ReturnTypeWithAnnotations = returnType; RefKind = refKind; diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs index 3408a1512a63e..a95e0fcb29572 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs @@ -465,7 +465,7 @@ public SynthesizedOperatorParameterSymbol( TypeSymbol type, int ordinal, string name - ) : base(container, TypeWithAnnotations.Create(type), ordinal, RefKind.None, DeclarationScope.Unscoped, name) + ) : base(container, TypeWithAnnotations.Create(type), ordinal, RefKind.None, ScopedKind.None, name) { } @@ -504,6 +504,8 @@ internal override MarshalPseudoCustomAttributeData MarshallingInformation { get { return null; } } + + internal override bool HasUnscopedRefAttribute => false; } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedLocal.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedLocal.cs index 62a8805780e20..604f3b675b906 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedLocal.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedLocal.cs @@ -9,7 +9,6 @@ using System.Diagnostics; using System.Runtime.CompilerServices; using System.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Symbols { @@ -17,7 +16,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols /// A synthesized local variable. /// [DebuggerDisplay("{GetDebuggerDisplay(),nq}")] - internal class SynthesizedLocal : LocalSymbol + internal sealed class SynthesizedLocal : LocalSymbol { private readonly MethodSymbol _containingMethodOpt; private readonly TypeWithAnnotations _type; @@ -71,7 +70,14 @@ public SyntaxNode SyntaxOpt get { return _syntaxOpt; } } - internal sealed override LocalSymbol WithSynthesizedLocalKindAndSyntax(SynthesizedLocalKind kind, SyntaxNode syntax) + internal sealed override LocalSymbol WithSynthesizedLocalKindAndSyntax( + SynthesizedLocalKind kind, SyntaxNode syntax +#if DEBUG + , + [CallerLineNumber] int createdAtLineNumber = 0, + [CallerFilePath] string createdAtFilePath = null +#endif + ) { return new SynthesizedLocal( _containingMethodOpt, @@ -80,7 +86,13 @@ internal sealed override LocalSymbol WithSynthesizedLocalKindAndSyntax(Synthesiz syntax, _isPinned, _isKnownToReferToTempIfReferenceType, - _refKind); + _refKind +#if DEBUG + , + createdAtLineNumber, + createdAtFilePath +#endif + ); } public sealed override RefKind RefKind @@ -170,19 +182,7 @@ internal sealed override bool IsCompilerGenerated get { return true; } } - /// - /// Compiler should always be synthesizing locals with correct escape semantics. - /// Checking escape scopes is not valid here. - /// - internal override uint ValEscapeScope => throw ExceptionUtilities.Unreachable(); - - /// - /// Compiler should always be synthesizing locals with correct escape semantics. - /// Checking escape scopes is not valid here. - /// - internal sealed override uint RefEscapeScope => throw ExceptionUtilities.Unreachable(); - - internal sealed override DeclarationScope Scope => DeclarationScope.Unscoped; + internal sealed override ScopedKind Scope => ScopedKind.None; internal sealed override ConstantValue GetConstantValue(SyntaxNode node, LocalSymbol inProgress, BindingDiagnosticBag diagnostics) { diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs index 3a7bd01ef9f5c..7a15d2be2e7f1 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs @@ -20,14 +20,14 @@ internal abstract class SynthesizedParameterSymbolBase : ParameterSymbol private readonly int _ordinal; private readonly string _name; private readonly RefKind _refKind; - private readonly DeclarationScope _scope; + private readonly ScopedKind _scope; public SynthesizedParameterSymbolBase( MethodSymbol? container, TypeWithAnnotations type, int ordinal, RefKind refKind, - DeclarationScope scope, + ScopedKind scope, string name) { Debug.Assert(type.HasType); @@ -80,6 +80,8 @@ internal override ConstantValue? ExplicitDefaultConstantValue get { return null; } } + internal virtual ConstantValue? DefaultValueFromAttributes => null; + internal override bool IsIDispatchConstant { get { throw ExceptionUtilities.Unreachable(); } @@ -179,19 +181,36 @@ internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, r AddSynthesizedAttribute(ref attributes, moduleBuilder.SynthesizeIsReadOnlyAttribute(this)); } + if (this.HasUnscopedRefAttribute && this.ContainingSymbol is SynthesizedDelegateInvokeMethod) + { + AddSynthesizedAttribute(ref attributes, compilation.TrySynthesizeAttribute(WellKnownMember.System_Diagnostics_CodeAnalysis_UnscopedRefAttribute__ctor)); + } + if (this.IsParams && this.ContainingSymbol is SynthesizedDelegateInvokeMethod) { AddSynthesizedAttribute(ref attributes, compilation.TrySynthesizeAttribute(WellKnownMember.System_ParamArrayAttribute__ctor)); } + + var defaultValue = this.ExplicitDefaultConstantValue; + if (defaultValue != ConstantValue.NotAvailable && + DefaultValueFromAttributes == ConstantValue.NotAvailable && + this.ContainingSymbol is SynthesizedDelegateInvokeMethod or SynthesizedClosureMethod) + { + var attrData = defaultValue.SpecialType switch + { + SpecialType.System_Decimal => compilation.SynthesizeDecimalConstantAttribute(defaultValue.DecimalValue), + SpecialType.System_DateTime => compilation.SynthesizeDateTimeConstantAttribute(defaultValue.DateTimeValue), + _ => null + }; + AddSynthesizedAttribute(ref attributes, attrData); + } } internal override ImmutableArray InterpolatedStringHandlerArgumentIndexes => ImmutableArray.Empty; internal override bool HasInterpolatedStringHandlerArgumentError => false; - internal sealed override DeclarationScope EffectiveScope => _scope; - - internal sealed override bool HasUnscopedRefAttribute => false; + internal sealed override ScopedKind EffectiveScope => _scope; internal sealed override bool UseUpdatedEscapeRules => _container?.UseUpdatedEscapeRules ?? false; } @@ -203,7 +222,7 @@ private SynthesizedParameterSymbol( TypeWithAnnotations type, int ordinal, RefKind refKind, - DeclarationScope scope, + ScopedKind scope, string name) : base(container, type, ordinal, refKind, scope, name) { @@ -219,13 +238,18 @@ public static ParameterSymbol Create( int ordinal, RefKind refKind, string name = "", - DeclarationScope scope = DeclarationScope.Unscoped, + ScopedKind scope = ScopedKind.None, ConstantValue? defaultValue = null, ImmutableArray refCustomModifiers = default, SourceComplexParameterSymbolBase? baseParameterForAttributes = null, - bool isParams = false) - { - if (!isParams && refCustomModifiers.IsDefaultOrEmpty && baseParameterForAttributes is null && defaultValue is null) + bool isParams = false, + bool hasUnscopedRefAttribute = false) + { + if (!isParams + && refCustomModifiers.IsDefaultOrEmpty + && baseParameterForAttributes is null + && defaultValue is null + && !hasUnscopedRefAttribute) { return new SynthesizedParameterSymbol(container, type, ordinal, refKind, scope, name); } @@ -240,7 +264,8 @@ public static ParameterSymbol Create( name, refCustomModifiers.NullToEmpty(), baseParameterForAttributes, - isParams); + isParams: isParams, + hasUnscopedRefAttribute: hasUnscopedRefAttribute); } /// @@ -282,6 +307,8 @@ internal override MarshalPseudoCustomAttributeData? MarshallingInformation { get { return null; } } + + internal override bool HasUnscopedRefAttribute => false; } internal sealed class SynthesizedComplexParameterSymbol : SynthesizedParameterSymbolBase @@ -292,28 +319,31 @@ internal sealed class SynthesizedComplexParameterSymbol : SynthesizedParameterSy private readonly SourceComplexParameterSymbolBase? _baseParameterForAttributes; private readonly ConstantValue? _defaultValue; private readonly bool _isParams; + private readonly bool _hasUnscopedRefAttribute; public SynthesizedComplexParameterSymbol( MethodSymbol? container, TypeWithAnnotations type, int ordinal, RefKind refKind, - DeclarationScope scope, + ScopedKind scope, ConstantValue? defaultValue, string name, ImmutableArray refCustomModifiers, SourceComplexParameterSymbolBase? baseParameterForAttributes, - bool isParams) + bool isParams, + bool hasUnscopedRefAttribute) : base(container, type, ordinal, refKind, scope, name) { Debug.Assert(!refCustomModifiers.IsDefault); - Debug.Assert(isParams || !refCustomModifiers.IsEmpty || baseParameterForAttributes is object || defaultValue is not null); + Debug.Assert(isParams || !refCustomModifiers.IsEmpty || baseParameterForAttributes is object || defaultValue is not null || hasUnscopedRefAttribute); Debug.Assert(baseParameterForAttributes is null || baseParameterForAttributes.ExplicitDefaultConstantValue == defaultValue); _refCustomModifiers = refCustomModifiers; _baseParameterForAttributes = baseParameterForAttributes; _defaultValue = defaultValue; _isParams = isParams; + _hasUnscopedRefAttribute = hasUnscopedRefAttribute; } public override ImmutableArray RefCustomModifiers @@ -332,6 +362,8 @@ public override ImmutableArray GetAttributes() public override bool IsParams => _isParams; + internal override bool HasUnscopedRefAttribute => _hasUnscopedRefAttribute; + internal override bool IsMetadataOptional => _baseParameterForAttributes?.IsMetadataOptional ?? base.IsMetadataOptional; internal override bool IsCallerLineNumber @@ -355,6 +387,8 @@ internal override bool IsCallerMemberName internal override ConstantValue? ExplicitDefaultConstantValue => _baseParameterForAttributes?.ExplicitDefaultConstantValue ?? _defaultValue; + internal override ConstantValue? DefaultValueFromAttributes => _baseParameterForAttributes?.DefaultValueFromAttributes; + internal override FlowAnalysisAnnotations FlowAnalysisAnnotations { get diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/TypeSubstitutedLocalSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/TypeSubstitutedLocalSymbol.cs index 671a4d4ce63f6..a0cd6788629cd 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/TypeSubstitutedLocalSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/TypeSubstitutedLocalSymbol.cs @@ -6,6 +6,7 @@ using System.Collections.Immutable; using System.Diagnostics; +using System.Runtime.CompilerServices; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Symbols @@ -107,19 +108,7 @@ public override RefKind RefKind /// Compiler should always be synthesizing locals with correct escape semantics. /// Checking escape scopes is not valid here. /// - internal override uint ValEscapeScope => throw ExceptionUtilities.Unreachable(); - - /// - /// Compiler should always be synthesizing locals with correct escape semantics. - /// Checking escape scopes is not valid here. - /// - internal override uint RefEscapeScope => throw ExceptionUtilities.Unreachable(); - - /// - /// Compiler should always be synthesizing locals with correct escape semantics. - /// Checking escape scopes is not valid here. - /// - internal override DeclarationScope Scope => throw new System.NotImplementedException(); + internal override ScopedKind Scope => throw new System.NotImplementedException(); internal override ConstantValue GetConstantValue(SyntaxNode node, LocalSymbol inProgress, BindingDiagnosticBag diagnostics) { @@ -131,11 +120,25 @@ internal override ImmutableBindingDiagnostic GetConstantValueDia return _originalVariable.GetConstantValueDiagnostics(boundInitValue); } - internal override LocalSymbol WithSynthesizedLocalKindAndSyntax(SynthesizedLocalKind kind, SyntaxNode syntax) + internal override LocalSymbol WithSynthesizedLocalKindAndSyntax( + SynthesizedLocalKind kind, SyntaxNode syntax +#if DEBUG + , + [CallerLineNumber] int createdAtLineNumber = 0, + [CallerFilePath] string createdAtFilePath = null +#endif + ) { var origSynthesized = (SynthesizedLocal)_originalVariable; return new TypeSubstitutedLocalSymbol( - origSynthesized.WithSynthesizedLocalKindAndSyntax(kind, syntax), + origSynthesized.WithSynthesizedLocalKindAndSyntax( + kind, syntax +#if DEBUG + , + createdAtLineNumber, + createdAtFilePath +#endif + ), _type, _containingSymbol ); diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs index b9060db656c8b..e54ba4ee31898 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs @@ -1862,6 +1862,13 @@ static void checkMethodOverride( allowVariance: true, invokedAsExtensionMethod: false); } + + if (implementingMethod.HasUnscopedRefAttributeOnMethodOrProperty()) + { + diagnostics.Add( + ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, + GetImplicitImplementationDiagnosticLocation(implementedMethod, implementingType, implementingMethod)); + } } switch (interfaceMember.Kind) diff --git a/src/Compilers/CSharp/Portable/Symbols/UpdatedContainingSymbolLocal.cs b/src/Compilers/CSharp/Portable/Symbols/UpdatedContainingSymbolLocal.cs index 747f5e17be18e..dc1292c702d08 100644 --- a/src/Compilers/CSharp/Portable/Symbols/UpdatedContainingSymbolLocal.cs +++ b/src/Compilers/CSharp/Portable/Symbols/UpdatedContainingSymbolLocal.cs @@ -4,6 +4,7 @@ using System.Collections.Immutable; using System.Diagnostics; +using System.Runtime.CompilerServices; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Symbols @@ -88,17 +89,21 @@ public override bool Equals(Symbol other, TypeCompareKind compareKind) internal override bool IsPinned => _underlyingLocal.IsPinned; internal override bool IsKnownToReferToTempIfReferenceType => _underlyingLocal.IsKnownToReferToTempIfReferenceType; internal override bool IsCompilerGenerated => _underlyingLocal.IsCompilerGenerated; - internal override uint RefEscapeScope => _underlyingLocal.RefEscapeScope; - internal override uint ValEscapeScope => _underlyingLocal.ValEscapeScope; - internal override DeclarationScope Scope => _underlyingLocal.Scope; + internal override ScopedKind Scope => _underlyingLocal.Scope; internal override ConstantValue GetConstantValue(SyntaxNode node, LocalSymbol inProgress, BindingDiagnosticBag? diagnostics = null) => _underlyingLocal.GetConstantValue(node, inProgress, diagnostics); internal override ImmutableBindingDiagnostic GetConstantValueDiagnostics(BoundExpression boundInitValue) => _underlyingLocal.GetConstantValueDiagnostics(boundInitValue); internal override SyntaxNode GetDeclaratorSyntax() => _underlyingLocal.GetDeclaratorSyntax(); - internal override LocalSymbol WithSynthesizedLocalKindAndSyntax(SynthesizedLocalKind kind, SyntaxNode syntax) => - throw ExceptionUtilities.Unreachable(); + internal override LocalSymbol WithSynthesizedLocalKindAndSyntax( + SynthesizedLocalKind kind, SyntaxNode syntax +#if DEBUG + , + [CallerLineNumber] int createdAtLineNumber = 0, + [CallerFilePath] string? createdAtFilePath = null +#endif + ) => throw ExceptionUtilities.Unreachable(); #endregion } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedParameterSymbol.cs index 4b875568929ce..2bd370437e2c1 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedParameterSymbol.cs @@ -152,7 +152,7 @@ public override string GetDocumentationCommentXml(CultureInfo? preferredCulture return _underlyingParameter.GetDocumentationCommentXml(preferredCulture, expandIncludes, cancellationToken); } - internal sealed override DeclarationScope EffectiveScope => _underlyingParameter.EffectiveScope; + internal sealed override ScopedKind EffectiveScope => _underlyingParameter.EffectiveScope; internal override bool HasUnscopedRefAttribute => _underlyingParameter.HasUnscopedRefAttribute; diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index a9aedb307a524..f223c7a11d737 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -369,7 +369,7 @@ A deconstruction variable cannot be declared as a ref local - A deconstruction variable cannot be declared as a ref local + Dekonstrukční proměnná nemůže být deklarovaná jako místní odkaz. @@ -759,7 +759,7 @@ Implicitly typed lambda parameter '{0}' cannot have a default value. - Implicitly typed lambda parameter '{0}' cannot have a default value. + Implicitně zadaný parametr lambda {0} nemůže mít výchozí hodnotu. @@ -1314,7 +1314,7 @@ Cannot ref-assign '{1}' to '{0}' because '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. - Cannot ref-assign '{1}' to '{0}' because '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. + Tento odkaz přiřazuje {1} k {0}, protože {1} má širší obor řídicích hodnot než {0}, který povoluje přiřazení prostřednictvím {0} hodnot s užšími řídicími obory než {1}. @@ -1439,7 +1439,7 @@ The 'scoped' modifier cannot be used with discard. - The 'scoped' modifier cannot be used with discard. + Modifikátor scoped nejde použít s proměnnou typu discard. @@ -1647,9 +1647,19 @@ {0} má atribut UnmanagedCallersOnly a nedá se převést na typ delegáta. Pro tuto metodu získejte ukazatel na funkci. UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute cannot be applied to an interface implementation. + UnscopedRefAttribute cannot be applied to an interface implementation. + + + + UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + + - UnscopedRefAttribute cannot be applied to this item because it is unscoped by default. - U této položky není možné použít atribut UnscopedRefAttribute, protože ve výchozím nastavení není nastaven obor. + UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. + UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. @@ -1789,12 +1799,12 @@ lambda optional parameters - lambda optional parameters + volitelné parametry lambda lambda params array - lambda params array + pole parametrů lambda @@ -1894,7 +1904,7 @@ <missing> - <missing> + <missing> @@ -2134,12 +2144,12 @@ Parameter {0} has default value '{1:10}' in lambda but '{2:10}' in the target delegate type. - Parameter {0} has default value '{1:10}' in lambda but '{2:10}' in the target delegate type. + Parametr {0} má výchozí hodnotu {1:10} ve výrazu lambda, ale v cílovém typu delegáta má {2:10}. The default parameter value does not match in the target delegate type. - The default parameter value does not match in the target delegate type. + Výchozí hodnota parametru neodpovídá v cílovém typu delegáta. @@ -2164,12 +2174,12 @@ Parameter {0} has params modifier in lambda but not in target delegate type. - Parameter {0} has params modifier in lambda but not in target delegate type. + Parametr {0} má modifikátor params ve výrazu lambda, ale ne v cílovém typu delegáta. Parameter has params modifier in lambda but not in target delegate type. - Parameter has params modifier in lambda but not in target delegate type. + Parametr má modifikátor params ve výrazu lambda, ale ne v cílovém typu delegáta. @@ -2229,12 +2239,12 @@ This ref-assigns '{1}' to '{0}' but '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. - This ref-assigns '{1}' to '{0}' but '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. + Tento odkaz přiřazuje {1} k {0}, ale {1} má širší obor řídicích hodnot než {0}, který povoluje přiřazení prostřednictvím {0} hodnot s užšími řídicími obory než {1}. This ref-assigns a value that has a wider value escape scope than the target allowing assignment through the target of values with narrower escapes scopes. - This ref-assigns a value that has a wider value escape scope than the target allowing assignment through the target of values with narrower escapes scopes. + Tento odkaz přiřazuje hodnotu, která má širší řídicí obor hodnot než cíl, který povoluje přiřazení prostřednictvím cíle hodnot s užšími řídicími obory. @@ -5318,7 +5328,7 @@ A non ref-returning property or indexer may not be used as an out or ref value - A non ref-returning property or indexer may not be used as an out or ref value + Vlastnost nebo indexer nevracející odkaz nejde použít jako hodnotu out nebo ref. @@ -8526,7 +8536,7 @@ Blok catch() po bloku catch (System.Exception e) může zachytit výjimky, kter Since this is an async method, the return expression must be of type '{0}' rather than '{1}' - Since this is an async method, the return expression must be of type '{0}' rather than '{1}' + Protože se jedná o asynchronní metodu, vrácený výraz musí být typu {0} a ne typu {1}. @@ -9689,7 +9699,7 @@ Poskytněte kompilátoru nějaký způsob, jak metody rozlišit. Můžete např Since '{0}' is an async method that returns '{1}', a return keyword must not be followed by an object expression - Since '{0}' is an async method that returns '{1}', a return keyword must not be followed by an object expression + Protože {0} je asynchronní metoda, která vrací {1}, nesmí za klíčovým slovem return následovat výraz objektu. @@ -11119,7 +11129,7 @@ Pokud chcete odstranit toto varování, můžete místo toho použít /reference Async lambda expression converted to a '{0}' returning delegate cannot return a value - Async lambda expression converted to a '{0}' returning delegate cannot return a value + Asynchronní výraz lambda převedený na návratový delegát {0}nemůže vrátit hodnotu. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 1f053dc83d52a..b6ebf4d36414c 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -369,7 +369,7 @@ A deconstruction variable cannot be declared as a ref local - A deconstruction variable cannot be declared as a ref local + Eine Dekonstruktionsvariable kann nicht als lokale Referenz deklariert werden. @@ -759,7 +759,7 @@ Implicitly typed lambda parameter '{0}' cannot have a default value. - Implicitly typed lambda parameter '{0}' cannot have a default value. + Der implizit eingegebene Parameter „{0}“ der Lambdafunktion darf keinen Standardwert aufweisen. @@ -1314,7 +1314,7 @@ Cannot ref-assign '{1}' to '{0}' because '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. - Cannot ref-assign '{1}' to '{0}' because '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. + „{1}“ kann nicht auf „{0}“ verweisen, da „{1}“ einen breiteren Werte-Escapebereich als „{0}“ hat, wodurch die Zuweisung über „{0}“ von Werten mit engeren Escapebereichen als „{1}“ ermöglicht wird. @@ -1439,7 +1439,7 @@ The 'scoped' modifier cannot be used with discard. - The 'scoped' modifier cannot be used with discard. + Der Modifizierer „scoped“ kann nicht mit „discard“ verwendet werden. @@ -1647,9 +1647,19 @@ "{0}" ist mit dem Attribut "UnmanagedCallersOnly" versehen und kann nicht in einen Delegattyp konvertiert werden. Rufen Sie einen Funktionszeiger auf diese Methode ab. UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute cannot be applied to an interface implementation. + UnscopedRefAttribute cannot be applied to an interface implementation. + + + + UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + + - UnscopedRefAttribute cannot be applied to this item because it is unscoped by default. - "UnscopedRefAttribute" kann nicht auf dieses Element angewendet werden, weil es standardmäßig keinen Gültigkeitsbereich aufweist. + UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. + UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. @@ -1789,12 +1799,12 @@ lambda optional parameters - lambda optional parameters + Optionale Parameter der Lambdafunktion lambda params array - lambda params array + Parameterarray der Lambdafunktion @@ -1894,7 +1904,7 @@ <missing> - <missing> + <missing> @@ -2134,12 +2144,12 @@ Parameter {0} has default value '{1:10}' in lambda but '{2:10}' in the target delegate type. - Parameter {0} has default value '{1:10}' in lambda but '{2:10}' in the target delegate type. + Der Parameter {0} hat den Standardwert „{1:10}“ in der Lambdafunktion, aber „{2:10}“ im Delegattyp des Ziels. The default parameter value does not match in the target delegate type. - The default parameter value does not match in the target delegate type. + Der Standardparameterwert stimmt nicht mit dem Delegattyp im Ziel überein. @@ -2164,12 +2174,12 @@ Parameter {0} has params modifier in lambda but not in target delegate type. - Parameter {0} has params modifier in lambda but not in target delegate type. + Der Parameter {0} weist den Modifizierer „params“ in der Lambdafunktion auf, aber nicht im Delegattyp des Ziels. Parameter has params modifier in lambda but not in target delegate type. - Parameter has params modifier in lambda but not in target delegate type. + Der Parameter verfügt über den Modifizierer „params“ in der Lambdafunktion, aber nicht im Delegattyp des Ziels. @@ -2229,12 +2239,12 @@ This ref-assigns '{1}' to '{0}' but '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. - This ref-assigns '{1}' to '{0}' but '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. + Dieser weist „{1}“ für „{0}“ zu, aber „{1}“ hat einen breiteren Werte-Escapebereich als „{0}“, wodurch die Zuweisung über „{0}“ von Werten mit engeren Escapebereichen als „{1}“ ermöglicht wird. This ref-assigns a value that has a wider value escape scope than the target allowing assignment through the target of values with narrower escapes scopes. - This ref-assigns a value that has a wider value escape scope than the target allowing assignment through the target of values with narrower escapes scopes. + Dies weist einen Wert zu, der über einen breiteren Werte-Escapebereich als das Ziel verfügt, wodurch die Zuweisung durch das Ziel von Werten mit engeren Escapebereichen ermöglicht wird. @@ -5318,7 +5328,7 @@ A non ref-returning property or indexer may not be used as an out or ref value - A non ref-returning property or indexer may not be used as an out or ref value + Eine Eigenschaft oder ein Indexer ohne Verweisrückgabe darf nicht als Out- oder Ref-Wert verwendet werden. @@ -8526,7 +8536,7 @@ Ein catch()-Block nach einem catch (System.Exception e)-Block kann nicht-CLS-Aus Since this is an async method, the return expression must be of type '{0}' rather than '{1}' - Since this is an async method, the return expression must be of type '{0}' rather than '{1}' + Da es sich um eine asynchrone Methode handelt, muss der Rückgabeausdruck vom Typ „{0}“ anstelle von „{1}“ sein. @@ -9689,7 +9699,7 @@ Unterstützen Sie den Compiler bei der Unterscheidung zwischen den Methoden. Daz Since '{0}' is an async method that returns '{1}', a return keyword must not be followed by an object expression - Since '{0}' is an async method that returns '{1}', a return keyword must not be followed by an object expression + Da „{0}“ eine asynchrone Methode ist, die „{1}“ zurückgibt, darf auf ein Rückgabeschlüsselwort kein Objektausdruck folgen. @@ -11119,7 +11129,7 @@ Um die Warnung zu beheben, können Sie stattdessen /reference verwenden (Einbett Async lambda expression converted to a '{0}' returning delegate cannot return a value - Async lambda expression converted to a '{0}' returning delegate cannot return a value + Eine asynchroner Lambdafunktion, die in einen zurückkehrenden „{0}“-Delegat konvertiert wurde, kann keinen Wert zurückgeben. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 06916cec41095..a7368e20a82d0 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -369,7 +369,7 @@ A deconstruction variable cannot be declared as a ref local - A deconstruction variable cannot be declared as a ref local + Una variable de deconstrucción no se puede declarar como ref local @@ -759,7 +759,7 @@ Implicitly typed lambda parameter '{0}' cannot have a default value. - Implicitly typed lambda parameter '{0}' cannot have a default value. + El parámetro lambda con tipo implícito “{0}” no puede tener un valor predeterminado. @@ -1314,7 +1314,7 @@ Cannot ref-assign '{1}' to '{0}' because '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. - Cannot ref-assign '{1}' to '{0}' because '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. + No se puede asignar referencia de “{1}” a “{0}” porque “{1}” tiene un ámbito de escape de valor más amplio que “{0}” lo que permite la asignación mediante “{0}” de valores con ámbitos de escape más estrechos que “{1}”. @@ -1439,7 +1439,7 @@ The 'scoped' modifier cannot be used with discard. - The 'scoped' modifier cannot be used with discard. + El modificador “scoped” no se puede usar con discard. @@ -1647,9 +1647,19 @@ ' {0} ' tiene un atributo ' UnmanagedCallersOnly ' y no se puede convertir en un tipo de delegado. Obtenga un puntero de función a este método. UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute cannot be applied to an interface implementation. + UnscopedRefAttribute cannot be applied to an interface implementation. + + + + UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + + - UnscopedRefAttribute cannot be applied to this item because it is unscoped by default. - UnscopedRefAttribute no se puede aplicar a este elemento porque no tiene ámbito de forma predeterminada. + UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. + UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. @@ -1789,12 +1799,12 @@ lambda optional parameters - lambda optional parameters + parámetros opcionales lambda lambda params array - lambda params array + matriz de parámetros lambda @@ -1894,7 +1904,7 @@ <missing> - <missing> + <missing> @@ -2134,12 +2144,12 @@ Parameter {0} has default value '{1:10}' in lambda but '{2:10}' in the target delegate type. - Parameter {0} has default value '{1:10}' in lambda but '{2:10}' in the target delegate type. + El parámetro {0} tiene un valor predeterminado “{1:10}” en lambda pero “{2:10}” en el tipo delegado de destino. The default parameter value does not match in the target delegate type. - The default parameter value does not match in the target delegate type. + El valor del parámetro predeterminado no coincide en el tipo delegado de destino. @@ -2164,12 +2174,12 @@ Parameter {0} has params modifier in lambda but not in target delegate type. - Parameter {0} has params modifier in lambda but not in target delegate type. + El parámetro {0} tiene modificador de parámetros en lambda, pero no en el tipo delegado de destino. Parameter has params modifier in lambda but not in target delegate type. - Parameter has params modifier in lambda but not in target delegate type. + El parámetro tiene modificador de parámetros en lambda, pero no en el tipo delegado de destino. @@ -2229,12 +2239,12 @@ This ref-assigns '{1}' to '{0}' but '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. - This ref-assigns '{1}' to '{0}' but '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. + Esta referencia asigna “{1}” a “{0}” pero “{1}” tiene un ámbito de escape de valor más amplio que “{0}” lo que permite la asignación mediante “{0}” de valores con ámbitos de escape más estrechos que “{1}”. This ref-assigns a value that has a wider value escape scope than the target allowing assignment through the target of values with narrower escapes scopes. - This ref-assigns a value that has a wider value escape scope than the target allowing assignment through the target of values with narrower escapes scopes. + Esta referencia asigna un valor que tiene un ámbito de escape de valor más amplio que el destino lo que permite la asignación a través del destino de valores con ámbitos de escape más estrechos. @@ -5318,7 +5328,7 @@ A non ref-returning property or indexer may not be used as an out or ref value - A non ref-returning property or indexer may not be used as an out or ref value + No se puede usar una propiedad o indizador que no devuelva referencias como valor out o ref @@ -8526,7 +8536,7 @@ Un bloque catch() después de un bloque catch (System.Exception e) puede abarcar Since this is an async method, the return expression must be of type '{0}' rather than '{1}' - Since this is an async method, the return expression must be of type '{0}' rather than '{1}' + Dado que se trata de un método asincrónico, la expresión devuelta debe ser de tipo '{0}' en lugar de ''{1}'' @@ -9689,7 +9699,7 @@ Indique al compilador alguna forma de diferenciar los métodos. Por ejemplo, pue Since '{0}' is an async method that returns '{1}', a return keyword must not be followed by an object expression - Since '{0}' is an async method that returns '{1}', a return keyword must not be followed by an object expression + Dado que '{0}' es un método asincrónico que devuelve '{1}', una palabra clave devuelta no debe ir seguida de una expresión de objeto @@ -11119,7 +11129,7 @@ Para eliminar la advertencia puede usar /reference (establezca la propiedad Embe Async lambda expression converted to a '{0}' returning delegate cannot return a value - Async lambda expression converted to a '{0}' returning delegate cannot return a value + La expresión lambda asincrónica convertida en un delegado que devuelve "{0}" no puede devolver un valor diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index f47d2660d7597..61e2a1fd17256 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -369,7 +369,7 @@ A deconstruction variable cannot be declared as a ref local - A deconstruction variable cannot be declared as a ref local + Une variable de déconstruction ne peut pas être déclaré en tant que variable locale @@ -759,7 +759,7 @@ Implicitly typed lambda parameter '{0}' cannot have a default value. - Implicitly typed lambda parameter '{0}' cannot have a default value. + Le paramètre d’expression lambda implicitement typé '{0}' ne peut pas avoir de valeur par défaut. @@ -1314,7 +1314,7 @@ Cannot ref-assign '{1}' to '{0}' because '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. - Cannot ref-assign '{1}' to '{0}' because '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. + Cette référence ne peut affecter '{1}' à '{0}', car '{1}' a une étendue d’échappement de valeur plus large que '{0}' permettant l’affectation via '{0}' de valeurs avec des étendues d’échappement plus restreintes que '{1}'. @@ -1439,7 +1439,7 @@ The 'scoped' modifier cannot be used with discard. - The 'scoped' modifier cannot be used with discard. + Le modificateur « Scoped » ne peut pas être utilisé avec discard. @@ -1647,9 +1647,19 @@ '{0}' est attribué avec 'UnmanagedCallersOnly' et ne peut pas être converti en type délégué. Obtenez un pointeur de fonction vers cette méthode. UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute cannot be applied to an interface implementation. + UnscopedRefAttribute cannot be applied to an interface implementation. + + + + UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + + - UnscopedRefAttribute cannot be applied to this item because it is unscoped by default. - UnscopedRefAttribute ne peut pas être appliqué à cet élément, car il n’a pas d’étendue par défaut. + UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. + UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. @@ -1789,12 +1799,12 @@ lambda optional parameters - lambda optional parameters + paramètres optionnels d’expression lambda lambda params array - lambda params array + tableau des paramètres de l’expression lambda @@ -1894,7 +1904,7 @@ <missing> - <missing> + <manquant> @@ -2134,12 +2144,12 @@ Parameter {0} has default value '{1:10}' in lambda but '{2:10}' in the target delegate type. - Parameter {0} has default value '{1:10}' in lambda but '{2:10}' in the target delegate type. + Le paramètre {0} a une valeur par défaut '{1:10}' dans l’expression lambda, mais a '{2:10}' dans le type délégué cible. The default parameter value does not match in the target delegate type. - The default parameter value does not match in the target delegate type. + La valeur du paramètre par défaut ne correspond pas au type délégué cible. @@ -2164,12 +2174,12 @@ Parameter {0} has params modifier in lambda but not in target delegate type. - Parameter {0} has params modifier in lambda but not in target delegate type. + Le paramètre {0} a un modificateur de paramètres dans l’expression lambda mais pas dans le type délégué cible. Parameter has params modifier in lambda but not in target delegate type. - Parameter has params modifier in lambda but not in target delegate type. + Le paramètre a un modificateur de paramètres dans l’expression lambda mais pas dans le type délégué cible. @@ -2229,12 +2239,12 @@ This ref-assigns '{1}' to '{0}' but '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. - This ref-assigns '{1}' to '{0}' but '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. + Cette référence affecte '{1}' à '{0}', mais '{1}' a une étendue d’échappement de valeur plus large que '{0}' permettant l’affectation via '{0}' de valeurs avec des étendues d’échappement plus restreintes que '{1}'. This ref-assigns a value that has a wider value escape scope than the target allowing assignment through the target of values with narrower escapes scopes. - This ref-assigns a value that has a wider value escape scope than the target allowing assignment through the target of values with narrower escapes scopes. + Cette référence affecte une valeur, mais a une étendue d’échappement de valeur plus large que la cible, ce qui permet l’affectation via la cible de valeurs avec des étendues d’échappement plus restreintes. @@ -5318,7 +5328,7 @@ A non ref-returning property or indexer may not be used as an out or ref value - A non ref-returning property or indexer may not be used as an out or ref value + Une propriété ou un indexeur qui ne retourne pas une référence ne peut pas être utilisé en tant que valeur ou référence de sortie @@ -8526,7 +8536,7 @@ Un bloc catch() après un bloc catch (System.Exception e) peut intercepter des e Since this is an async method, the return expression must be of type '{0}' rather than '{1}' - Since this is an async method, the return expression must be of type '{0}' rather than '{1}' + S'agissant d'une méthode asynchrone, l'expression de retour doit être de type « {0} » plutôt que « {1} » @@ -9689,7 +9699,7 @@ Permettez au compilateur de différencier les méthodes. Par exemple, vous pouve Since '{0}' is an async method that returns '{1}', a return keyword must not be followed by an object expression - Since '{0}' is an async method that returns '{1}', a return keyword must not be followed by an object expression + Comme « {0} » est une méthode asynchrone qui renvoie « {1} », un mot clé de retour ne doit pas être suivi d’une expression d’objet @@ -11119,7 +11129,7 @@ Pour supprimer l'avertissement, vous pouvez utiliser la commande /reference (dé Async lambda expression converted to a '{0}' returning delegate cannot return a value - Async lambda expression converted to a '{0}' returning delegate cannot return a value + Une expression lambda convertie en délégué retournant « {0} » ne peut pas retourner une valeur diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 6ba59c7137056..49e372571e97c 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -369,7 +369,7 @@ A deconstruction variable cannot be declared as a ref local - A deconstruction variable cannot be declared as a ref local + Una variabile di decostruzione non può essere dichiarata come variabile locale di riferimento @@ -759,7 +759,7 @@ Implicitly typed lambda parameter '{0}' cannot have a default value. - Implicitly typed lambda parameter '{0}' cannot have a default value. + Il parametro lambda tipizzato in modo implicito '{0}' non può avere un valore predefinito. @@ -1314,7 +1314,7 @@ Cannot ref-assign '{1}' to '{0}' because '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. - Cannot ref-assign '{1}' to '{0}' because '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. + Non è possibile ref-assign '{1}' a '{0}' perché '{1}' ha un ambito di escape del valore più ampio di '{0}' consentendo l'assegnazione tramite '{0}' di valori con ambiti di escape più ristretti rispetto a '{1}'. @@ -1439,7 +1439,7 @@ The 'scoped' modifier cannot be used with discard. - The 'scoped' modifier cannot be used with discard. + Non è possibile usare il modificatore 'scoped' con discard. @@ -1647,9 +1647,19 @@ '{0}', a cui è assegnato l'attributo 'UnmanagedCallersOnly', non può essere convertito in un tipo delegato. Ottenere un puntatore a funzione per questo metodo. UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute cannot be applied to an interface implementation. + UnscopedRefAttribute cannot be applied to an interface implementation. + + + + UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + + - UnscopedRefAttribute cannot be applied to this item because it is unscoped by default. - Non è possibile applicare UnscopedRefAttribute a questo elemento perché è senza ambito per impostazione predefinita. + UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. + UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. @@ -1789,12 +1799,12 @@ lambda optional parameters - lambda optional parameters + parametri facoltativi lambda lambda params array - lambda params array + matrice di parametri lambda @@ -1894,7 +1904,7 @@ <missing> - <missing> + <missing> @@ -2134,12 +2144,12 @@ Parameter {0} has default value '{1:10}' in lambda but '{2:10}' in the target delegate type. - Parameter {0} has default value '{1:10}' in lambda but '{2:10}' in the target delegate type. + Il parametro {0} ha il valore predefinito '{1:10}' nell'espressione lambda ma '{2:10}' nel tipo delegato di destinazione. The default parameter value does not match in the target delegate type. - The default parameter value does not match in the target delegate type. + Il valore del parametro predefinito non corrisponde al tipo delegato di destinazione. @@ -2164,12 +2174,12 @@ Parameter {0} has params modifier in lambda but not in target delegate type. - Parameter {0} has params modifier in lambda but not in target delegate type. + Il parametro {0} contiene un modificatore di parametri in lambda ma non nel tipo delegato di destinazione. Parameter has params modifier in lambda but not in target delegate type. - Parameter has params modifier in lambda but not in target delegate type. + Il parametro contiene un modificatore di parametri in lambda ma non nel tipo delegato di destinazione. @@ -2229,12 +2239,12 @@ This ref-assigns '{1}' to '{0}' but '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. - This ref-assigns '{1}' to '{0}' but '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. + Questo riferimento assegna '{1}' a '{0}' ma '{1}' ha un ambito di escape del valore più ampio di '{0}' consentendo l'assegnazione tramite '{0}' di valori con ambiti di escape più ristretti rispetto a '{1}'. This ref-assigns a value that has a wider value escape scope than the target allowing assignment through the target of values with narrower escapes scopes. - This ref-assigns a value that has a wider value escape scope than the target allowing assignment through the target of values with narrower escapes scopes. + Questa funzione assegna un valore che ha un ambito di escape più ampio di quello del target, consentendo l'assegnazione attraverso il target di valori con ambiti di escape più ristretti. @@ -5318,7 +5328,7 @@ A non ref-returning property or indexer may not be used as an out or ref value - A non ref-returning property or indexer may not be used as an out or ref value + Una proprietà o un indicizzatore che non restituisce ref non possono essere usati come valori out o ref. @@ -8526,7 +8536,7 @@ Un blocco catch() dopo un blocco catch (System.Exception e) può rilevare eccezi Since this is an async method, the return expression must be of type '{0}' rather than '{1}' - Since this is an async method, the return expression must be of type '{0}' rather than '{1}' + Poiché si tratta di un metodo asincrono, l'espressione restituita deve essere di tipo '{0}' anziché '{1}' @@ -9689,7 +9699,7 @@ Impostare il compilatore in modo tale da distinguere i metodi, ad esempio assegn Since '{0}' is an async method that returns '{1}', a return keyword must not be followed by an object expression - Since '{0}' is an async method that returns '{1}', a return keyword must not be followed by an object expression + Poiché '{0}' è un metodo asincrono che restituisce '{1}', una parola chiave di restituzione non deve essere seguita da un'espressione di oggetto @@ -11119,7 +11129,7 @@ Per rimuovere l'avviso, è invece possibile usare /reference (impostare la propr Async lambda expression converted to a '{0}' returning delegate cannot return a value - Async lambda expression converted to a '{0}' returning delegate cannot return a value + L'espressione lambda asincrona convertita in un delegato che restituisce '{0}' non può restituire un valore diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 9d64b5c4a4729..92e5ddd223c98 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -369,7 +369,7 @@ A deconstruction variable cannot be declared as a ref local - A deconstruction variable cannot be declared as a ref local + 分解変数を ref ローカルと宣言することはできません @@ -759,7 +759,7 @@ Implicitly typed lambda parameter '{0}' cannot have a default value. - Implicitly typed lambda parameter '{0}' cannot have a default value. + 暗黙的に型指定されたラムダパラメーター '{0}' に既定値を指定することはできません。 @@ -1314,7 +1314,7 @@ Cannot ref-assign '{1}' to '{0}' because '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. - Cannot ref-assign '{1}' to '{0}' because '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. + '{1}' を '{0}' に参照割り当てできません。'{1}' には '{0}' よりも広い値エスケープ スコープがあり、'{0}' を使用して '{1}' より狭いエスケープ スコープを持つ値の割り当てが許可されています。 @@ -1439,7 +1439,7 @@ The 'scoped' modifier cannot be used with discard. - The 'scoped' modifier cannot be used with discard. + 'scoped' 修飾子を discard と共に使用することはできません。 @@ -1647,9 +1647,19 @@ '{0}' は 'UnmanagedCallersOnly' 属性が設定されているため、デリゲート型に変換できません。このメソッドへの関数ポインターを取得してください。 UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute cannot be applied to an interface implementation. + UnscopedRefAttribute cannot be applied to an interface implementation. + + + + UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + + - UnscopedRefAttribute cannot be applied to this item because it is unscoped by default. - UnscopedRefAttribute は、既定では範囲外であるため、この項目に適用できません。 + UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. + UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. @@ -1789,12 +1799,12 @@ lambda optional parameters - lambda optional parameters + ラムダの省略可能なパラメーター lambda params array - lambda params array + ラムダ パラメーター配列 @@ -1894,7 +1904,7 @@ <missing> - <missing> + <missing> @@ -2134,12 +2144,12 @@ Parameter {0} has default value '{1:10}' in lambda but '{2:10}' in the target delegate type. - Parameter {0} has default value '{1:10}' in lambda but '{2:10}' in the target delegate type. + パラメーター {0} のラムダでの既定値は '{1:10}' だが、ターゲットデリゲート型では '{2:10}' です。 The default parameter value does not match in the target delegate type. - The default parameter value does not match in the target delegate type. + 既定のパラメーター値がターゲット デリゲート型と一致しません。 @@ -2164,12 +2174,12 @@ Parameter {0} has params modifier in lambda but not in target delegate type. - Parameter {0} has params modifier in lambda but not in target delegate type. + パラメーター {0} にラムダの params 修飾子がありますが、ターゲット デリゲート型にはありません。 Parameter has params modifier in lambda but not in target delegate type. - Parameter has params modifier in lambda but not in target delegate type. + パラメーターにラムダの params 修飾子がありますが、ターゲット デリゲート型にはありません。 @@ -2229,12 +2239,12 @@ This ref-assigns '{1}' to '{0}' but '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. - This ref-assigns '{1}' to '{0}' but '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. + この参照は '{1}' に '{0}' を割り当てますが、'{1}' の値のエスケープ スコープは、'{0}' よりも狭いエスケープ スコープを持つ値の'{0}' を介した割り当てを許可する '{1}' よりも広い値のエスケープ スコープを持っています。 This ref-assigns a value that has a wider value escape scope than the target allowing assignment through the target of values with narrower escapes scopes. - This ref-assigns a value that has a wider value escape scope than the target allowing assignment through the target of values with narrower escapes scopes. + この参照により、ターゲットよりも広い値エスケープ スコープを持つ値が割り当てられ、より狭いエスケープ スコープを持つ値のターゲットを介して割り当てることができます。 @@ -5318,7 +5328,7 @@ A non ref-returning property or indexer may not be used as an out or ref value - A non ref-returning property or indexer may not be used as an out or ref value + 参照を返さないプロパティまたはインデクサーを out 値または ref 値として使用することはできません @@ -8526,7 +8536,7 @@ AssemblyInfo.cs ファイルで RuntimeCompatibilityAttribute が false に設 Since this is an async method, the return expression must be of type '{0}' rather than '{1}' - Since this is an async method, the return expression must be of type '{0}' rather than '{1}' + これは非同期メソッドであるため、return 式は '{0}' ではなく '{1}' 型である必要があります @@ -9689,7 +9699,7 @@ C# では out と ref を区別しますが、CLR では同じと認識します Since '{0}' is an async method that returns '{1}', a return keyword must not be followed by an object expression - Since '{0}' is an async method that returns '{1}', a return keyword must not be followed by an object expression + '{0}' は '{1}' を返す非同期メソッドであるため、return キーワードの後にオブジェクト式を続けてはなりません @@ -11119,7 +11129,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Async lambda expression converted to a '{0}' returning delegate cannot return a value - Async lambda expression converted to a '{0}' returning delegate cannot return a value + デリゲートを返す '{0}' に変換された非同期ラムダ式は値を返すことができません diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 1894bf49133a0..7d9f91ff678a1 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -369,7 +369,7 @@ A deconstruction variable cannot be declared as a ref local - A deconstruction variable cannot be declared as a ref local + 분해 변수는 참조 로컬로 선언할 수 없습니다. @@ -759,7 +759,7 @@ Implicitly typed lambda parameter '{0}' cannot have a default value. - Implicitly typed lambda parameter '{0}' cannot have a default value. + 암시적 형식 람다 매개 변수 '{0}'은(는) 기본값을 가질 수 없습니다. @@ -1314,7 +1314,7 @@ Cannot ref-assign '{1}' to '{0}' because '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. - Cannot ref-assign '{1}' to '{0}' because '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. + '{0}'에 '{1}'을(를) ref-assign할 수 없습니다. '{1}'은(는) '{0}'보다 더 넓은 값 이스케이프 범위를 가지며 '{1}'보다 좁은 이스케이프 범위가 있는 값의 '{0}'을(를) 통한 할당을 허용합니다. @@ -1439,7 +1439,7 @@ The 'scoped' modifier cannot be used with discard. - The 'scoped' modifier cannot be used with discard. + 'scoped' 한정자는 무시 항목과 함께 사용할 수 없습니다. @@ -1647,9 +1647,19 @@ '{0}'에는 'UnmanagedCallersOnly' 특성이 지정되어 있으며 이 항목은 대리자 형식으로 변환할 수 없습니다. 이 메서드에 대한 함수 포인터를 가져오세요. UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute cannot be applied to an interface implementation. + UnscopedRefAttribute cannot be applied to an interface implementation. + + + + UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + + - UnscopedRefAttribute cannot be applied to this item because it is unscoped by default. - UnscopedRefAttribute는 기본적으로 범위가 지정되지 않기 때문에 이 항목에 적용할 수 없습니다. + UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. + UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. @@ -1789,12 +1799,12 @@ lambda optional parameters - lambda optional parameters + 람다 선택적 매개 변수 lambda params array - lambda params array + 람다 매개 변수 배열 @@ -1894,7 +1904,7 @@ <missing> - <missing> + <missing> @@ -2134,12 +2144,12 @@ Parameter {0} has default value '{1:10}' in lambda but '{2:10}' in the target delegate type. - Parameter {0} has default value '{1:10}' in lambda but '{2:10}' in the target delegate type. + {0} 매개 변수는 람다에서 '{1:10}' 기본값을 가지지만 대상 대리자 형식에서는 '{2:10}'을 가집니다. The default parameter value does not match in the target delegate type. - The default parameter value does not match in the target delegate type. + 기본 매개 변수 값이 대상 대리자 형식과 일치하지 않습니다. @@ -2164,12 +2174,12 @@ Parameter {0} has params modifier in lambda but not in target delegate type. - Parameter {0} has params modifier in lambda but not in target delegate type. + {0} 매개 변수에 람다의 매개 변수 한정자가 있지만 대상 대리자 형식에는 없습니다. Parameter has params modifier in lambda but not in target delegate type. - Parameter has params modifier in lambda but not in target delegate type. + 매개 변수에 람다의 매개 변수 한정자가 있지만 대상 대리자 형식에는 없습니다. @@ -2229,12 +2239,12 @@ This ref-assigns '{1}' to '{0}' but '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. - This ref-assigns '{1}' to '{0}' but '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. + 이는 '{0}'에 '{1}'을(를) ref-assign하지만 '{1}'은(는) '{0}'보다 더 넓은 값 이스케이프 범위를 가지며 '{1}'보다 좁은 이스케이프 범위가 있는 값의 '{0}'을(를) 통한 할당을 허용합니다. This ref-assigns a value that has a wider value escape scope than the target allowing assignment through the target of values with narrower escapes scopes. - This ref-assigns a value that has a wider value escape scope than the target allowing assignment through the target of values with narrower escapes scopes. + 이는 대상보다 더 넓은 값 이스케이프 범위를 가지는 값을 ref-assign하며 더 좁은 이스케이프 범위가 있는 값의 대상을 통한 할당을 허용합니다. @@ -5317,7 +5327,7 @@ A non ref-returning property or indexer may not be used as an out or ref value - A non ref-returning property or indexer may not be used as an out or ref value + 참조를 반환하지 않는 속성 또는 인덱서는 out 또는 ref 값으로 사용할 수 없음 @@ -8525,7 +8535,7 @@ catch (System.Exception e) 블록 뒤의 catch() 블록은 RuntimeCompatibilityA Since this is an async method, the return expression must be of type '{0}' rather than '{1}' - Since this is an async method, the return expression must be of type '{0}' rather than '{1}' + 비동기 메서드이므로 반환 식이 '{1}' 형식이 아니라 '{0}' 형식이어야 합니다. @@ -9688,7 +9698,7 @@ C#에서는 out과 ref를 구분하지만 CLR에서는 동일한 것으로 간 Since '{0}' is an async method that returns '{1}', a return keyword must not be followed by an object expression - Since '{0}' is an async method that returns '{1}', a return keyword must not be followed by an object expression + '{0}'은(는) '{1}'을(를) 반환하는 비동기 메서드이므로 반환 키워드 뒤에 개체 식이 있으면 안 됩니다. @@ -11118,7 +11128,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Async lambda expression converted to a '{0}' returning delegate cannot return a value - Async lambda expression converted to a '{0}' returning delegate cannot return a value + '{0}' 반환 대리자로 변환된 비동기 람다 식은 값을 반환할 수 없습니다. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 8a7f63805d971..09cda4f156f53 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -369,7 +369,7 @@ A deconstruction variable cannot be declared as a ref local - A deconstruction variable cannot be declared as a ref local + Nie można zadeklarować zmiennej dekonstrukcji jako lokalnej wartości ref @@ -759,7 +759,7 @@ Implicitly typed lambda parameter '{0}' cannot have a default value. - Implicitly typed lambda parameter '{0}' cannot have a default value. + Niejawnie typizowany parametr wyrażenia lambda „{0}” nie może mieć wartości domyślnej. @@ -1314,7 +1314,7 @@ Cannot ref-assign '{1}' to '{0}' because '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. - Cannot ref-assign '{1}' to '{0}' because '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. + Nie można przypisać wartości ref „{1}” do „{0}”, ponieważ „{1}” ma szerszy zakres ucieczki wartości niż „{0}”, umożliwiając przypisanie za pośrednictwem „{0}” wartości z węższymi zakresami ucieczki niż „{1}”. @@ -1439,7 +1439,7 @@ The 'scoped' modifier cannot be used with discard. - The 'scoped' modifier cannot be used with discard. + Modyfikator „scoped” nie może być używany z odrzuceniem. @@ -1647,9 +1647,19 @@ Element „{0}” ma atrybut „UnmanagedCallersOnly” i nie można go przekonwertować na typ delegowany. Uzyskaj wskaźnik funkcji do tej metody. UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute cannot be applied to an interface implementation. + UnscopedRefAttribute cannot be applied to an interface implementation. + + + + UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + + - UnscopedRefAttribute cannot be applied to this item because it is unscoped by default. - Nie można zastosować atrybutu UnscopedRefAttribute do tego elementu, ponieważ jest on domyślnie nieobjęty zakresem. + UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. + UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. @@ -1789,12 +1799,12 @@ lambda optional parameters - lambda optional parameters + opcjonalne parametry wyrażenia lambda lambda params array - lambda params array + tablica parametrów lambda @@ -1894,7 +1904,7 @@ <missing> - <missing> + <missing> @@ -2134,12 +2144,12 @@ Parameter {0} has default value '{1:10}' in lambda but '{2:10}' in the target delegate type. - Parameter {0} has default value '{1:10}' in lambda but '{2:10}' in the target delegate type. + Parametr {0} ma wartość domyślną „{1:10}” w wyrażeniu lambda, ale wartość „{2:10}” w docelowym typie delegata. The default parameter value does not match in the target delegate type. - The default parameter value does not match in the target delegate type. + Domyślna wartość parametru nie jest zgodna w docelowym typie delegata. @@ -2164,12 +2174,12 @@ Parameter {0} has params modifier in lambda but not in target delegate type. - Parameter {0} has params modifier in lambda but not in target delegate type. + Parametr {0} ma modyfikator params w wyrażeniu lambda, ale nie ma w docelowym typie delegata. Parameter has params modifier in lambda but not in target delegate type. - Parameter has params modifier in lambda but not in target delegate type. + Parametr ma modyfikator params w wyrażeniu lambda, ale nie ma w docelowym typie delegata. @@ -2229,12 +2239,12 @@ This ref-assigns '{1}' to '{0}' but '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. - This ref-assigns '{1}' to '{0}' but '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. + Ta wartość ref przypisuje „{1}” do „{0}”, ale „{1}” ma szerszy zakres ucieczki wartości niż „{0}”, umożliwiając przypisanie za pośrednictwem „{0}” wartości z węższymi zakresami ucieczki niż „{1}”. This ref-assigns a value that has a wider value escape scope than the target allowing assignment through the target of values with narrower escapes scopes. - This ref-assigns a value that has a wider value escape scope than the target allowing assignment through the target of values with narrower escapes scopes. + Ta wartość ref przypisuje wartość, która ma szerszy zakres ucieczki wartości niż wartość docelowa, umożliwiając przypisanie za pośrednictwem wartości docelowej wartości z węższymi zakresami ucieczki. @@ -5318,7 +5328,7 @@ A non ref-returning property or indexer may not be used as an out or ref value - A non ref-returning property or indexer may not be used as an out or ref value + Nie można używać właściwości zwracającej inną wartość niż ref lub indeksatora jako wartości out lub ref @@ -8526,7 +8536,7 @@ Blok catch() po bloku catch (System.Exception e) może przechwytywać wyjątki n Since this is an async method, the return expression must be of type '{0}' rather than '{1}' - Since this is an async method, the return expression must be of type '{0}' rather than '{1}' + Ponieważ jest to metoda asynchroniczna, zwracane wyrażenie musi być typu „{0}”, a nie „{1}” @@ -9689,7 +9699,7 @@ Musisz umożliwić kompilatorowi rozróżnienie metod. Możesz na przykład nada Since '{0}' is an async method that returns '{1}', a return keyword must not be followed by an object expression - Since '{0}' is an async method that returns '{1}', a return keyword must not be followed by an object expression + Ponieważ „{0}” jest metodą asynchroniczną, która zwraca wartość „{1}”, po zwrotnym słowie kluczowym nie może występować wyrażenie obiektu. @@ -11119,7 +11129,7 @@ Aby usunąć ostrzeżenie, możesz zamiast tego użyć opcji /reference (ustaw w Async lambda expression converted to a '{0}' returning delegate cannot return a value - Async lambda expression converted to a '{0}' returning delegate cannot return a value + Asynchroniczne wyrażenie lambda przekonwertowana na delegata zwracającego „{0}” nie może zwracać wartości diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index f1568ba610012..9871535b0ca9e 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -369,7 +369,7 @@ A deconstruction variable cannot be declared as a ref local - A deconstruction variable cannot be declared as a ref local + Uma variável de desconstrução não pode ser declarada como ref local @@ -759,7 +759,7 @@ Implicitly typed lambda parameter '{0}' cannot have a default value. - Implicitly typed lambda parameter '{0}' cannot have a default value. + O parâmetro lambda '{0}' digitado implicitamente não pode ter um valor padrão. @@ -1314,7 +1314,7 @@ Cannot ref-assign '{1}' to '{0}' because '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. - Cannot ref-assign '{1}' to '{0}' because '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. + Não é possível atribuir novamente '{1}' a '{0}' porque '{1}' tem um escopo de escape de valor maior que '{0}' permitindo a atribuição por meio de '{0}' de valores com escopos de escape mais estreitos do que '{1}'. @@ -1439,7 +1439,7 @@ The 'scoped' modifier cannot be used with discard. - The 'scoped' modifier cannot be used with discard. + O modificador 'scoped' não pode ser usado com descarte. @@ -1647,9 +1647,19 @@ '{0}' foi atribuído com 'UnmanagedCallersOnly' e não pode ser convertido em um tipo delegado. Obtenha um ponteiro de função para esse método. UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute cannot be applied to an interface implementation. + UnscopedRefAttribute cannot be applied to an interface implementation. + + + + UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + + - UnscopedRefAttribute cannot be applied to this item because it is unscoped by default. - UnscopedRefAttribute não pode ser aplicado a este item porque não tem escopo por padrão. + UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. + UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. @@ -1789,12 +1799,12 @@ lambda optional parameters - lambda optional parameters + Parâmetros opcionais lambda lambda params array - lambda params array + Matriz de parâmetros lambda @@ -1894,7 +1904,7 @@ <missing> - <missing> + <ausente> @@ -2134,12 +2144,12 @@ Parameter {0} has default value '{1:10}' in lambda but '{2:10}' in the target delegate type. - Parameter {0} has default value '{1:10}' in lambda but '{2:10}' in the target delegate type. + O parâmetro {0} tem o valor padrão '{1:10}' em lambda, mas '{2:10}' no tipo delegado de destino. The default parameter value does not match in the target delegate type. - The default parameter value does not match in the target delegate type. + O valor do parâmetro padrão não corresponde ao tipo delegado de destino. @@ -2164,12 +2174,12 @@ Parameter {0} has params modifier in lambda but not in target delegate type. - Parameter {0} has params modifier in lambda but not in target delegate type. + O parâmetro {0} tem o modificador de parâmetros em lambda, mas não no tipo delegado de destino. Parameter has params modifier in lambda but not in target delegate type. - Parameter has params modifier in lambda but not in target delegate type. + O parâmetro tem modificador de parâmetros em lambda, mas não no tipo delegado de destino. @@ -2229,12 +2239,12 @@ This ref-assigns '{1}' to '{0}' but '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. - This ref-assigns '{1}' to '{0}' but '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. + Esta referência atribui '{1}' a '{0}', mas '{1}' tem um escopo de escape de valor maior do que '{0}' permitindo a atribuição por meio de '{0}' de valores com escopos de escape mais estreitos do que '{1}'. This ref-assigns a value that has a wider value escape scope than the target allowing assignment through the target of values with narrower escapes scopes. - This ref-assigns a value that has a wider value escape scope than the target allowing assignment through the target of values with narrower escapes scopes. + Essa referência atribui um valor que tem um escopo de escape de valor mais amplo do que o destino permitindo a atribuição por meio do destino de valores com escopos de escape mais estreitos. @@ -5318,7 +5328,7 @@ A non ref-returning property or indexer may not be used as an out or ref value - A non ref-returning property or indexer may not be used as an out or ref value + Talvez uma propriedade ou um indexador sem retorno de ref não pode ser usado como um valor out ou ref @@ -8526,7 +8536,7 @@ Um bloco catch() depois de um bloco catch (System.Exception e) poderá capturar Since this is an async method, the return expression must be of type '{0}' rather than '{1}' - Since this is an async method, the return expression must be of type '{0}' rather than '{1}' + Como este é um método assíncrono, a expressão de retorno deve ser do tipo "{0}" em vez de "{1}" @@ -9689,7 +9699,7 @@ Forneça ao compilador alguma forma de diferenciar os métodos. Por exemplo, voc Since '{0}' is an async method that returns '{1}', a return keyword must not be followed by an object expression - Since '{0}' is an async method that returns '{1}', a return keyword must not be followed by an object expression + Como '{0}' é um método assíncrono que retorna '{1}', uma palavra-chave de retorno não deve ser seguida por uma expressão de objeto @@ -11119,7 +11129,7 @@ Para incorporar informações de tipo de interoperabilidade para os dois assembl Async lambda expression converted to a '{0}' returning delegate cannot return a value - Async lambda expression converted to a '{0}' returning delegate cannot return a value + A expressão lambda assíncrona convertida em um representante de retorno '{0}' não pode retornar um valor diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index d166bfd9c34d4..29ea07b55ec1f 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -369,7 +369,7 @@ A deconstruction variable cannot be declared as a ref local - A deconstruction variable cannot be declared as a ref local + Переменная деконструирования не может быть объявлена как локальная переменная ref @@ -759,7 +759,7 @@ Implicitly typed lambda parameter '{0}' cannot have a default value. - Implicitly typed lambda parameter '{0}' cannot have a default value. + Неявно типизованный параметр "{0}" не может иметь значение по умолчанию. @@ -1314,7 +1314,7 @@ Cannot ref-assign '{1}' to '{0}' because '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. - Cannot ref-assign '{1}' to '{0}' because '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. + Не удается присвоить по ссылке "{1}" "{0}", потому что "{1}" имеет более широкую область выхода, чем "{0}", что позволяет присваивать через "{0}" значения с более узкими областями выхода, чем "{1}". @@ -1439,7 +1439,7 @@ The 'scoped' modifier cannot be used with discard. - The 'scoped' modifier cannot be used with discard. + Модификатор "scoped" нельзя использовать с отменой. @@ -1647,9 +1647,19 @@ "{0}" имеет атрибут "UnmanagedCallersOnly" и не может быть преобразован в тип делегата. Получите указатель на функцию для этого метода. UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute cannot be applied to an interface implementation. + UnscopedRefAttribute cannot be applied to an interface implementation. + + + + UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + + - UnscopedRefAttribute cannot be applied to this item because it is unscoped by default. - Не удается применить UnscopedRefAttribute к этому элементу, так как у него по умолчанию нет области действия. + UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. + UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. @@ -1789,12 +1799,12 @@ lambda optional parameters - lambda optional parameters + дополнительные параметры лямбды lambda params array - lambda params array + массив лямбда-параметров @@ -1894,7 +1904,7 @@ <missing> - <missing> + <missing> @@ -2134,12 +2144,12 @@ Parameter {0} has default value '{1:10}' in lambda but '{2:10}' in the target delegate type. - Parameter {0} has default value '{1:10}' in lambda but '{2:10}' in the target delegate type. + Параметр {0} имеет значение по умолчанию "{1:10}" в лямбде, но "{2:10}" в типе целевого делегата. The default parameter value does not match in the target delegate type. - The default parameter value does not match in the target delegate type. + Значение параметра по умолчанию не совпадает с типом целевого делегата. @@ -2164,12 +2174,12 @@ Parameter {0} has params modifier in lambda but not in target delegate type. - Parameter {0} has params modifier in lambda but not in target delegate type. + У параметра {0} есть модификатор params в лямбде, но не в типе целевого делегата. Parameter has params modifier in lambda but not in target delegate type. - Parameter has params modifier in lambda but not in target delegate type. + У параметра есть модификатор params в лямбде, но не в типе целевого делегата. @@ -2229,12 +2239,12 @@ This ref-assigns '{1}' to '{0}' but '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. - This ref-assigns '{1}' to '{0}' but '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. + Это присваивает по ссылке "{1}" "{0}", но "{1}" имеет более широкую область выхода, чем "{0}", что позволяет присваивать через "{0}" значения с более узкими областями выхода, чем "{1}". This ref-assigns a value that has a wider value escape scope than the target allowing assignment through the target of values with narrower escapes scopes. - This ref-assigns a value that has a wider value escape scope than the target allowing assignment through the target of values with narrower escapes scopes. + Это присваивает по ссылке значение, которое имеет более широкую область выхода, чем цель, что позволяет присваивать через цель значения с более узкими областями выхода. @@ -5318,7 +5328,7 @@ A non ref-returning property or indexer may not be used as an out or ref value - A non ref-returning property or indexer may not be used as an out or ref value + Свойство или индексатор, не возвращающие значения, не могут использоваться в качестве значения out или ref. @@ -8526,7 +8536,7 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep Since this is an async method, the return expression must be of type '{0}' rather than '{1}' - Since this is an async method, the return expression must be of type '{0}' rather than '{1}' + Поскольку данный метод является асинхронным, возвращаемое выражение должно относиться к типу "{0}", а не к типу "{1}". @@ -9689,7 +9699,7 @@ Give the compiler some way to differentiate the methods. For example, you can gi Since '{0}' is an async method that returns '{1}', a return keyword must not be followed by an object expression - Since '{0}' is an async method that returns '{1}', a return keyword must not be followed by an object expression + Поскольку "{0}" является асинхронным методом, возвращающим "{1}", за ключевым словом return не может следовать выражение объекта @@ -11119,7 +11129,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Async lambda expression converted to a '{0}' returning delegate cannot return a value - Async lambda expression converted to a '{0}' returning delegate cannot return a value + Асинхронное лямбда-выражение, преобразованное в делегата, возвращающего "{0}", не может возвращать значение diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index a2dd9b5b55ca8..6648846eec821 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -369,7 +369,7 @@ A deconstruction variable cannot be declared as a ref local - A deconstruction variable cannot be declared as a ref local + Ayrıştırma değişkeni, ref yerel olarak bildirilemez @@ -759,7 +759,7 @@ Implicitly typed lambda parameter '{0}' cannot have a default value. - Implicitly typed lambda parameter '{0}' cannot have a default value. + Türü örtük olarak belirlenmiş lambda '{0}' parametresi varsayılan bir değere sahip olamaz. @@ -1314,7 +1314,7 @@ Cannot ref-assign '{1}' to '{0}' because '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. - Cannot ref-assign '{1}' to '{0}' because '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. + '{1}' başvuru değeri, '{0}' olarak atanamaz çünkü '{1}' değeri '{0}' değerinden daha geniş bir değer kaçış kapsamına sahip olduğundan '{1}' değerinden daha dar kaçış kapsamlarına sahip '{0}' değeri üzerinden atamaya izin verir. @@ -1439,7 +1439,7 @@ The 'scoped' modifier cannot be used with discard. - The 'scoped' modifier cannot be used with discard. + 'scoped' değiştiricisi atma ile kullanılamaz. @@ -1647,9 +1647,19 @@ '{0}', 'UnmanagedCallersOnly' özniteliğine sahip ve temsilci türüne dönüştürülemez. Bu yöntem için bir işlev işaretçisi edinin. UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute cannot be applied to an interface implementation. + UnscopedRefAttribute cannot be applied to an interface implementation. + + + + UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + + - UnscopedRefAttribute cannot be applied to this item because it is unscoped by default. - UnscopedRefAttribute varsayılan olarak kapsam dışı olduğundan bu öğeye uygulanamaz. + UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. + UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. @@ -1789,12 +1799,12 @@ lambda optional parameters - lambda optional parameters + lambda isteğe bağlı parametreleri lambda params array - lambda params array + lambda parametreleri dizisi @@ -1894,7 +1904,7 @@ <missing> - <missing> + <missing> @@ -2134,12 +2144,12 @@ Parameter {0} has default value '{1:10}' in lambda but '{2:10}' in the target delegate type. - Parameter {0} has default value '{1:10}' in lambda but '{2:10}' in the target delegate type. + {0} parametresi, lambdada '{1:10}' varsayılan değerine ancak temsilci türünde ise '{2:10}' değerine sahip. The default parameter value does not match in the target delegate type. - The default parameter value does not match in the target delegate type. + Varsayılan parametre değeri hedef temsilci türünde eşleşmiyor. @@ -2164,12 +2174,12 @@ Parameter {0} has params modifier in lambda but not in target delegate type. - Parameter {0} has params modifier in lambda but not in target delegate type. + {0} parametresi, lambda içinde parametre değiştiricisi içeriyor ancak hedef temsilci türünde içermiyor. Parameter has params modifier in lambda but not in target delegate type. - Parameter has params modifier in lambda but not in target delegate type. + Parametre, lambda içinde parametre değiştiricisi içeriyor ancak hedef temsilci türünde içermiyor. @@ -2229,12 +2239,12 @@ This ref-assigns '{1}' to '{0}' but '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. - This ref-assigns '{1}' to '{0}' but '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. + Bu başvuru, '{1}' değerini '{0}' olarak atar ancak '{1}' değeri '{0}' değerinden daha geniş bir değer kaçış kapsamına sahip olduğundan '{1}' değerinden daha dar kaçış kapsamlarına sahip '{0}' değeri üzerinden atamaya izin verir. This ref-assigns a value that has a wider value escape scope than the target allowing assignment through the target of values with narrower escapes scopes. - This ref-assigns a value that has a wider value escape scope than the target allowing assignment through the target of values with narrower escapes scopes. + Bu başvuru, hedeften daha geniş bir değer kaçış kapsamına sahip bir değer atadığından daha dar kaçış kapsamlarına sahip değerlerin hedefi üzerinden atamaya izin verir. @@ -5318,7 +5328,7 @@ A non ref-returning property or indexer may not be used as an out or ref value - A non ref-returning property or indexer may not be used as an out or ref value + Başvuru döndürmeyen bir özellik veya dizin oluşturucu, out veya ref değeri olarak kullanılamaz @@ -8526,7 +8536,7 @@ RuntimeCompatibilityAttribute AssemblyInfo.cs dosyasında false olarak ayarlanm Since this is an async method, the return expression must be of type '{0}' rather than '{1}' - Since this is an async method, the return expression must be of type '{0}' rather than '{1}' + Bu, zaman uyumsuz bir yöntem olduğundan, döndürme ifadesi '{1}' türü yerine '{0}' türünde olmalıdır @@ -9689,7 +9699,7 @@ Derleyiciye yöntemleri ayrıştırma yolu verin. Örneğin, bunlara farklı adl Since '{0}' is an async method that returns '{1}', a return keyword must not be followed by an object expression - Since '{0}' is an async method that returns '{1}', a return keyword must not be followed by an object expression + '{0}', '{1}' döndüren bir zaman uyumsuz yöntem olduğundan döndürme anahtar sözcüğünün ardından nesne ifadesi gelmemelidir. @@ -11119,7 +11129,7 @@ Uyarıyı kaldırmak için, /reference kullanabilirsiniz (Birlikte Çalışma T Async lambda expression converted to a '{0}' returning delegate cannot return a value - Async lambda expression converted to a '{0}' returning delegate cannot return a value + '{0}' döndüren zaman uyumsuz lambda ifadesi dönüştürülen temsilci, bir değer döndüremez diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index 42002eb0fb6dc..384ba86ae4b83 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -369,7 +369,7 @@ A deconstruction variable cannot be declared as a ref local - A deconstruction variable cannot be declared as a ref local + 析构变量不能声明为 ref 局部变量 @@ -759,7 +759,7 @@ Implicitly typed lambda parameter '{0}' cannot have a default value. - Implicitly typed lambda parameter '{0}' cannot have a default value. + 隐式键入的 lambda 参数 "{0}" 不能具有默认值。 @@ -1314,7 +1314,7 @@ Cannot ref-assign '{1}' to '{0}' because '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. - Cannot ref-assign '{1}' to '{0}' because '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. + 无法将 "{1}" ref-assign 给 "{0}",因为 "{1}" 比 "{0}" 具有更广的值转义范围,允许通过转义范围比 "{1}" 更窄的值的 "{0}" 进行赋值。 @@ -1439,7 +1439,7 @@ The 'scoped' modifier cannot be used with discard. - The 'scoped' modifier cannot be used with discard. + "scoped" 修饰符不能与 discard 一起使用。 @@ -1647,9 +1647,19 @@ “{0}”使用 "UnmanagedCallersOnly" 进行特性化,无法转换为委托类型。请获取指向此方法的函数指针。 UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute cannot be applied to an interface implementation. + UnscopedRefAttribute cannot be applied to an interface implementation. + + + + UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + + - UnscopedRefAttribute cannot be applied to this item because it is unscoped by default. - 无法将 UnscopedRefAttribute 应用于此项,因为默认情况下未限定其范围。 + UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. + UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. @@ -1789,12 +1799,12 @@ lambda optional parameters - lambda optional parameters + lambda 可选参数 lambda params array - lambda params array + lambda 参数数组 @@ -1894,7 +1904,7 @@ <missing> - <missing> + <missing> @@ -2134,12 +2144,12 @@ Parameter {0} has default value '{1:10}' in lambda but '{2:10}' in the target delegate type. - Parameter {0} has default value '{1:10}' in lambda but '{2:10}' in the target delegate type. + 参数 {0} 在 lambda 中具有默认值 "{1:10}",但在目标委托类型中为 "{2:10}"。 The default parameter value does not match in the target delegate type. - The default parameter value does not match in the target delegate type. + 默认参数值在目标委托类型中不匹配。 @@ -2164,12 +2174,12 @@ Parameter {0} has params modifier in lambda but not in target delegate type. - Parameter {0} has params modifier in lambda but not in target delegate type. + 参数 {0} 在 lambda 中具有参数修饰符,但在目标委托类型中没有参数修饰符。 Parameter has params modifier in lambda but not in target delegate type. - Parameter has params modifier in lambda but not in target delegate type. + 参数在 lambda 中具有参数修饰符,但在目标委托类型中没有参数修饰符。 @@ -2229,12 +2239,12 @@ This ref-assigns '{1}' to '{0}' but '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. - This ref-assigns '{1}' to '{0}' but '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. + 它会将 "{1}" ref-assign 给 "{0}",但 "{1}" 比 "{0}" 具有更广的值转义范围,允许通过转义范围比 "{1}" 更窄的值的 "{0}" 进行赋值。 This ref-assigns a value that has a wider value escape scope than the target allowing assignment through the target of values with narrower escapes scopes. - This ref-assigns a value that has a wider value escape scope than the target allowing assignment through the target of values with narrower escapes scopes. + 它会 ref-assign 一个值转义范围大于目标的值,允许通过转义范围更窄的值的目标进行赋值。 @@ -5323,7 +5333,7 @@ A non ref-returning property or indexer may not be used as an out or ref value - A non ref-returning property or indexer may not be used as an out or ref value + 非引用返回属性或索引器不能用作 out 或 ref 值 @@ -8531,7 +8541,7 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep Since this is an async method, the return expression must be of type '{0}' rather than '{1}' - Since this is an async method, the return expression must be of type '{0}' rather than '{1}' + 这是一个异步方法,因此返回表达式的类型必须为“{0}”而不是“{1}” @@ -9694,7 +9704,7 @@ Give the compiler some way to differentiate the methods. For example, you can gi Since '{0}' is an async method that returns '{1}', a return keyword must not be followed by an object expression - Since '{0}' is an async method that returns '{1}', a return keyword must not be followed by an object expression + 由于 "{0}" 是返回 "{1}" 的异步方法,因此返回关键字不得后跟对象表达式 @@ -11124,7 +11134,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Async lambda expression converted to a '{0}' returning delegate cannot return a value - Async lambda expression converted to a '{0}' returning delegate cannot return a value + 转换为 "{0}" 的异步 lambda 表达式无法返回值 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 9ddf0cb1e50ac..9be3c25141d71 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -369,7 +369,7 @@ A deconstruction variable cannot be declared as a ref local - A deconstruction variable cannot be declared as a ref local + 解構變數不可宣告為參考本機 @@ -759,7 +759,7 @@ Implicitly typed lambda parameter '{0}' cannot have a default value. - Implicitly typed lambda parameter '{0}' cannot have a default value. + 隱含輸入的 Lambda 參數 '{0}' 不能有預設值。 @@ -1314,7 +1314,7 @@ Cannot ref-assign '{1}' to '{0}' because '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. - Cannot ref-assign '{1}' to '{0}' because '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. + 無法參考指派 '{1}' 給 '{0}',因為 '{1}' 具有比 '{0}' 更寬的值逸出範圍,允許透過 '{0}' 的值指派,其逸出範圍比 '{1}' 更窄。 @@ -1439,7 +1439,7 @@ The 'scoped' modifier cannot be used with discard. - The 'scoped' modifier cannot be used with discard. + 'scoped' 修飾元不能與捨棄一起使用。 @@ -1647,9 +1647,19 @@ '{0}' 使用 'UnmanagedCallersOnly' 屬性化,因此無法轉換為委派類型。取得此方法的函式指標。 UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute cannot be applied to an interface implementation. + UnscopedRefAttribute cannot be applied to an interface implementation. + + + + UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + + - UnscopedRefAttribute cannot be applied to this item because it is unscoped by default. - UnscopedRefAttribute 無法套用到此項目,因為預設是不限範圍。 + UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. + UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. @@ -1789,12 +1799,12 @@ lambda optional parameters - lambda optional parameters + Lambda 選用參數 lambda params array - lambda params array + Lambda 參數陣列 @@ -1894,7 +1904,7 @@ <missing> - <missing> + <missing> @@ -2134,12 +2144,12 @@ Parameter {0} has default value '{1:10}' in lambda but '{2:10}' in the target delegate type. - Parameter {0} has default value '{1:10}' in lambda but '{2:10}' in the target delegate type. + 參數 {0} 在 Lambda 中的預設值為 '{1:10}',但在目標委派類型中為 '{2:10}'。 The default parameter value does not match in the target delegate type. - The default parameter value does not match in the target delegate type. + 目標委派類型中的預設參數值不相符。 @@ -2164,12 +2174,12 @@ Parameter {0} has params modifier in lambda but not in target delegate type. - Parameter {0} has params modifier in lambda but not in target delegate type. + 參數 {0} 在 Lambda 中具有參數修飾元,但不在目標委派類型中。 Parameter has params modifier in lambda but not in target delegate type. - Parameter has params modifier in lambda but not in target delegate type. + 參數在 Lambda 中具有參數修飾元,但不在目標委派類型中。 @@ -2229,12 +2239,12 @@ This ref-assigns '{1}' to '{0}' but '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. - This ref-assigns '{1}' to '{0}' but '{1}' has a wider value escape scope than '{0}' allowing assignment through '{0}' of values with narrower escapes scopes than '{1}'. + 此參考指派 '{1}' 給 '{0}' 但 '{1}' 具有比 '{0}' 更寬的值逸出範圍,允許透過 '{0}' 的值指派,其逸出範圍比 '{1}' 更窄。 This ref-assigns a value that has a wider value escape scope than the target allowing assignment through the target of values with narrower escapes scopes. - This ref-assigns a value that has a wider value escape scope than the target allowing assignment through the target of values with narrower escapes scopes. + 此參考指派的值比目標的逸出範圍更寬,允許透過目標的值指派,其逸出範圍更窄。 @@ -5318,7 +5328,7 @@ A non ref-returning property or indexer may not be used as an out or ref value - A non ref-returning property or indexer may not be used as an out or ref value + 非參考傳回屬性或索引子不可以 out 或 ref 值形式使用 @@ -8526,7 +8536,7 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep Since this is an async method, the return expression must be of type '{0}' rather than '{1}' - Since this is an async method, the return expression must be of type '{0}' rather than '{1}' + 因為此為非同步方法,所以傳回運算式的類型必須是 '{0}' 而非 '{1}' @@ -9689,7 +9699,7 @@ Give the compiler some way to differentiate the methods. For example, you can gi Since '{0}' is an async method that returns '{1}', a return keyword must not be followed by an object expression - Since '{0}' is an async method that returns '{1}', a return keyword must not be followed by an object expression + 因為 '{0}' 是個會傳回 '{1}' 的非同步方法,所以傳回關鍵字之後不可接著物件運算式。 @@ -11119,7 +11129,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Async lambda expression converted to a '{0}' returning delegate cannot return a value - Async lambda expression converted to a '{0}' returning delegate cannot return a value + 轉換成 '{0}' 傳回委派的非同步 Lambda 運算式,不可傳回值 diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenConditionalOperatorTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenConditionalOperatorTests.cs index 3daeccaa04c99..074ccda8e2bd0 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenConditionalOperatorTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenConditionalOperatorTests.cs @@ -2964,31 +2964,41 @@ public static void Main() 0 -1 +0 hello hello"); verify.VerifyIL("C.Print()", @" { - // Code size 48 (0x30) - .maxstack 1 - .locals init (T V_0) //temp + // Code size 73 (0x49) + .maxstack 2 + .locals init (T V_0, //temp + T V_1) IL_0000: ldarg.0 IL_0001: ldfld ""T C.t"" IL_0006: stloc.0 - IL_0007: ldloc.0 - IL_0008: box ""T"" - IL_000d: brtrue.s IL_0012 - IL_000f: ldnull - IL_0010: br.s IL_001f - IL_0012: ldloca.s V_0 - IL_0014: constrained. ""T"" - IL_001a: callvirt ""string object.ToString()"" - IL_001f: call ""void System.Console.WriteLine(string)"" - IL_0024: ldloc.0 - IL_0025: box ""T"" - IL_002a: call ""void System.Console.WriteLine(object)"" - IL_002f: ret + IL_0007: ldloca.s V_0 + IL_0009: ldloca.s V_1 + IL_000b: initobj ""T"" + IL_0011: ldloc.1 + IL_0012: box ""T"" + IL_0017: brtrue.s IL_002d + IL_0019: ldobj ""T"" + IL_001e: stloc.1 + IL_001f: ldloca.s V_1 + IL_0021: ldloc.1 + IL_0022: box ""T"" + IL_0027: brtrue.s IL_002d + IL_0029: pop + IL_002a: ldnull + IL_002b: br.s IL_0038 + IL_002d: constrained. ""T"" + IL_0033: callvirt ""string object.ToString()"" + IL_0038: call ""void System.Console.WriteLine(string)"" + IL_003d: ldloc.0 + IL_003e: box ""T"" + IL_0043: call ""void System.Console.WriteLine(object)"" + IL_0048: ret }"); } @@ -3178,5 +3188,163 @@ .locals init (System.ValueTuple V_0) IL_0029: ret }"); } + + [Fact, WorkItem(66152, "https://github.com/dotnet/roslyn/issues/66152")] + public void NullableSideEffects_01() + { + var source = @" +struct S1 +{ + private int count; + public override string ToString() + { + return (++count).ToString(); + } +} + +class Program +{ + static void Main() + { + var x1 = new S1?(new S1()); + System.Console.Write(Test1(ref x1)); + System.Console.Write(x1.ToString()); + x1 = null; + System.Console.Write(Test1(ref x1) is null); + } + + static string Test1(ref T x) + { + return x?.ToString(); + } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: "11True").VerifyDiagnostics(); + verifier.VerifyIL("Program.Test1(ref T)", @" +{ + // Code size 48 (0x30) + .maxstack 2 + .locals init (T V_0) + IL_0000: ldarg.0 + IL_0001: ldloca.s V_0 + IL_0003: initobj ""T"" + IL_0009: ldloc.0 + IL_000a: box ""T"" + IL_000f: brtrue.s IL_0024 + IL_0011: ldobj ""T"" + IL_0016: stloc.0 + IL_0017: ldloca.s V_0 + IL_0019: ldloc.0 + IL_001a: box ""T"" + IL_001f: brtrue.s IL_0024 + IL_0021: pop + IL_0022: ldnull + IL_0023: ret + IL_0024: constrained. ""T"" + IL_002a: callvirt ""string object.ToString()"" + IL_002f: ret +} +"); + } + + [Fact, WorkItem(66152, "https://github.com/dotnet/roslyn/issues/66152")] + public void NullableSideEffects_02() + { + var source = @" +struct S1 +{ + private int count; + public override string ToString() + { + return (++count).ToString(); + } +} + +class Program +{ + static void Main() + { + var x1 = new S1?(new S1()); + System.Console.Write(Test1(ref x1)); + System.Console.Write(x1.ToString()); + x1 = null; + System.Console.Write(Test1(ref x1) is null); + } + + static string Test1(ref T x) + { + var y = x; + var result = y?.ToString(); + x = y; + return result; + } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: "11True").VerifyDiagnostics(); + verifier.VerifyIL("Program.Test1(ref T)", @" +{ + // Code size 64 (0x40) + .maxstack 3 + .locals init (T V_0, //y + T V_1) + IL_0000: ldarg.0 + IL_0001: ldobj ""T"" + IL_0006: stloc.0 + IL_0007: ldloca.s V_0 + IL_0009: ldloca.s V_1 + IL_000b: initobj ""T"" + IL_0011: ldloc.1 + IL_0012: box ""T"" + IL_0017: brtrue.s IL_002d + IL_0019: ldobj ""T"" + IL_001e: stloc.1 + IL_001f: ldloca.s V_1 + IL_0021: ldloc.1 + IL_0022: box ""T"" + IL_0027: brtrue.s IL_002d + IL_0029: pop + IL_002a: ldnull + IL_002b: br.s IL_0038 + IL_002d: constrained. ""T"" + IL_0033: callvirt ""string object.ToString()"" + IL_0038: ldarg.0 + IL_0039: ldloc.0 + IL_003a: stobj ""T"" + IL_003f: ret +} +"); + } + + [Fact, WorkItem(66152, "https://github.com/dotnet/roslyn/issues/66152")] + public void NullableSideEffects_03() + { + var source = @" +struct S1 +{ +} + +abstract class C0 +{ + public abstract string Test1(ref T x) where T : U; +} + +class C1 : C0 +{ + public override string Test1(ref T x) + { + var y = x; + var result = y?.ToString(); + x = y; + return result; + } +} +"; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (16,23): error CS0023: Operator '?' cannot be applied to operand of type 'T' + // var result = y?.ToString(); + Diagnostic(ErrorCode.ERR_BadUnaryOp, "?").WithArguments("?", "T").WithLocation(16, 23) + ); + } } } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenFunctionPointersTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenFunctionPointersTests.cs index a442f7093b6f0..ce0aa7abb8edd 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenFunctionPointersTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenFunctionPointersTests.cs @@ -10944,12 +10944,8 @@ static ref Span ReturnPtrByRef(delegate*, ref Span> ptr) Diagnostic(ErrorCode.WRN_RefReturnLocal, "span").WithArguments("span").WithLocation(10, 28) ); - // delegate*<,> parameter is implicitly scoped ref in C#11. comp = CreateCompilationWithSpan(source, options: TestOptions.UnsafeReleaseExe); comp.VerifyDiagnostics( - // (10,28): warning CS9080: Use of variable 'span' in this context may expose referenced variables outside of their declaration scope - // return ref ptr(ref span); - Diagnostic(ErrorCode.WRN_EscapeVariable, "span").WithArguments("span").WithLocation(10, 28), // (10,28): warning CS9091: This returns local 'span' by reference but it is not a ref local // return ref ptr(ref span); Diagnostic(ErrorCode.WRN_RefReturnLocal, "span").WithArguments("span").WithLocation(10, 28) diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenShortCircuitOperatorTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenShortCircuitOperatorTests.cs index 852509f4712f4..777339f813116 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenShortCircuitOperatorTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenShortCircuitOperatorTests.cs @@ -3184,15 +3184,26 @@ public static void CheckT(this T x) var comp = CompileAndVerify(source, references: new[] { CSharpRef }, expectedOutput: @"System.Nullable`1[System.Int64]"); comp.VerifyIL("Test.Test0(T)", @" { - // Code size 21 (0x15) - .maxstack 1 - IL_0000: ldarg.0 - IL_0001: box ""T"" - IL_0006: brfalse.s IL_0014 - IL_0008: ldarga.s V_0 - IL_000a: ldobj ""T"" - IL_000f: call ""void Ext.CheckT(T)"" - IL_0014: ret + // Code size 47 (0x2f) + .maxstack 2 + .locals init (T V_0) + IL_0000: ldarga.s V_0 + IL_0002: ldloca.s V_0 + IL_0004: initobj ""T"" + IL_000a: ldloc.0 + IL_000b: box ""T"" + IL_0010: brtrue.s IL_0024 + IL_0012: ldobj ""T"" + IL_0017: stloc.0 + IL_0018: ldloca.s V_0 + IL_001a: ldloc.0 + IL_001b: box ""T"" + IL_0020: brtrue.s IL_0024 + IL_0022: pop + IL_0023: ret + IL_0024: ldobj ""T"" + IL_0029: call ""void Ext.CheckT(T)"" + IL_002e: ret } "); } @@ -7000,27 +7011,27 @@ static void Main() verifier.VerifyIL("Test.Run", @" { - // Code size 45 (0x2d) + // Code size 43 (0x2b) .maxstack 2 .locals init (T V_0, string V_1) IL_0000: nop IL_0001: ldloca.s V_0 - IL_0003: initobj ""T"" - IL_0009: ldloc.0 - IL_000a: box ""T"" - IL_000f: brtrue.s IL_0014 - IL_0011: ldnull - IL_0012: br.s IL_0028 - IL_0014: ldloca.s V_0 - IL_0016: dup - IL_0017: initobj ""T"" - IL_001d: constrained. ""T"" - IL_0023: callvirt ""string object.ToString()"" - IL_0028: stloc.1 - IL_0029: br.s IL_002b - IL_002b: ldloc.1 - IL_002c: ret + IL_0003: dup + IL_0004: initobj ""T"" + IL_000a: dup + IL_000b: ldobj ""T"" + IL_0010: box ""T"" + IL_0015: brtrue.s IL_001b + IL_0017: pop + IL_0018: ldnull + IL_0019: br.s IL_0026 + IL_001b: constrained. ""T"" + IL_0021: callvirt ""string object.ToString()"" + IL_0026: stloc.1 + IL_0027: br.s IL_0029 + IL_0029: ldloc.1 + IL_002a: ret }"); } @@ -7060,25 +7071,35 @@ static void Main() verifier.VerifyIL("Test.Run", @" { - // Code size 38 (0x26) - .maxstack 1 + // Code size 63 (0x3f) + .maxstack 2 .locals init (T V_0, //v - string V_1) + T V_1, + string V_2) IL_0000: nop IL_0001: ldloca.s V_0 IL_0003: initobj ""T"" - IL_0009: ldloc.0 - IL_000a: box ""T"" - IL_000f: brtrue.s IL_0014 - IL_0011: ldnull - IL_0012: br.s IL_0021 - IL_0014: ldloca.s V_0 - IL_0016: constrained. ""T"" - IL_001c: callvirt ""string object.ToString()"" - IL_0021: stloc.1 - IL_0022: br.s IL_0024 - IL_0024: ldloc.1 - IL_0025: ret + IL_0009: ldloca.s V_0 + IL_000b: ldloca.s V_1 + IL_000d: initobj ""T"" + IL_0013: ldloc.1 + IL_0014: box ""T"" + IL_0019: brtrue.s IL_002f + IL_001b: ldobj ""T"" + IL_0020: stloc.1 + IL_0021: ldloca.s V_1 + IL_0023: ldloc.1 + IL_0024: box ""T"" + IL_0029: brtrue.s IL_002f + IL_002b: pop + IL_002c: ldnull + IL_002d: br.s IL_003a + IL_002f: constrained. ""T"" + IL_0035: callvirt ""string object.ToString()"" + IL_003a: stloc.2 + IL_003b: br.s IL_003d + IL_003d: ldloc.2 + IL_003e: ret }"); } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenStackAllocInitializerTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenStackAllocInitializerTests.cs index 24ca4f31d8f1c..9a6c654b9003f 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenStackAllocInitializerTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenStackAllocInitializerTests.cs @@ -583,6 +583,62 @@ .maxstack 4 }"); } + [Fact] + public void TestEnum() + { + var text = """ +using System; + +static unsafe class C +{ + static void Print(E* p) + { + for (int i = 0; i < 3; i++) + Console.Write(p[i]); + } + + static void Main() + { + var p1 = stackalloc[] { E.A, E.B, E.C }; + var p2 = stackalloc[] { E.D, E.D, E.D }; + + Print(p1); + Print(p2); + } + + enum E : byte { A, B, C, D } +} +"""; + CompileAndVerify(text, + options: TestOptions.UnsafeReleaseExe, + verify: Verification.Fails, expectedOutput: @"ABCDDD").VerifyIL("C.Main", +""" +{ + // Code size 35 (0x23) + .maxstack 4 + .locals init (C.E* V_0) //p1 + IL_0000: ldc.i4.3 + IL_0001: conv.u + IL_0002: localloc + IL_0004: dup + IL_0005: ldsflda ".__StaticArrayInitTypeSize=3 .AE4B3280E56E2FAF83F414A6E3DABE9D5FBE18976544C05FED121ACCB85B53FC" + IL_000a: ldc.i4.3 + IL_000b: cpblk + IL_000d: stloc.0 + IL_000e: ldc.i4.3 + IL_000f: conv.u + IL_0010: localloc + IL_0012: dup + IL_0013: ldc.i4.3 + IL_0014: ldc.i4.3 + IL_0015: initblk + IL_0017: ldloc.0 + IL_0018: call "void C.Print(C.E*)" + IL_001d: call "void C.Print(C.E*)" + IL_0022: ret +} +"""); + } [Fact] public void TestMixedBlockInit() { diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_LifetimeAnnotation.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_LifetimeAnnotation.cs index 476388dbfc2b9..38c30ad1dcda4 100644 --- a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_LifetimeAnnotation.cs +++ b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_LifetimeAnnotation.cs @@ -260,22 +260,22 @@ static void Main() var method = comp.GetMember("A.F1"); Assert.Equal("void A.F1(scoped R r)", method.ToTestDisplayString()); var parameter = method.Parameters[0]; - Assert.Equal(DeclarationScope.ValueScoped, parameter.EffectiveScope); + Assert.Equal(ScopedKind.ScopedValue, parameter.EffectiveScope); method = comp.GetMember("A.F2"); Assert.Equal("void A.F2(System.Int32 y)", method.ToTestDisplayString()); parameter = method.Parameters[0]; - Assert.Equal(DeclarationScope.Unscoped, parameter.EffectiveScope); + Assert.Equal(ScopedKind.None, parameter.EffectiveScope); method = comp.GetMember("A.F3"); Assert.Equal("void A.F3(System.Object x, scoped ref System.Int32 y)", method.ToTestDisplayString()); parameter = method.Parameters[1]; - Assert.Equal(DeclarationScope.RefScoped, parameter.EffectiveScope); + Assert.Equal(ScopedKind.ScopedRef, parameter.EffectiveScope); method = comp.GetMember("A.F4"); Assert.Equal("void A.F4(scoped ref R r)", method.ToTestDisplayString()); parameter = method.Parameters[0]; - Assert.Equal(DeclarationScope.RefScoped, parameter.EffectiveScope); + Assert.Equal(ScopedKind.ScopedRef, parameter.EffectiveScope); } [Fact] diff --git a/src/Compilers/CSharp/Test/Emit2/CodeGen/CodeGenCallTests.cs b/src/Compilers/CSharp/Test/Emit2/CodeGen/CodeGenCallTests.cs index 4156bee331030..4902fcc5433e1 100644 --- a/src/Compilers/CSharp/Test/Emit2/CodeGen/CodeGenCallTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/CodeGen/CodeGenCallTests.cs @@ -95,23 +95,22 @@ .maxstack 2 verifier.VerifyIL("Program.Call2", @" { - // Code size 45 (0x2d) + // Code size 46 (0x2e) .maxstack 2 .locals init (T V_0) IL_0000: ldarga.s V_0 - IL_0002: ldloca.s V_0 - IL_0004: initobj ""T"" - IL_000a: ldloc.0 - IL_000b: box ""T"" - IL_0010: brtrue.s IL_001a - IL_0012: ldobj ""T"" - IL_0017: stloc.0 - IL_0018: ldloca.s V_0 - IL_001a: ldarga.s V_0 - IL_001c: call ""int Program.GetOffset(ref T)"" - IL_0021: constrained. ""T"" - IL_0027: callvirt ""void IMoveable.GetName(int)"" - IL_002c: ret + IL_0002: ldtoken ""T"" + IL_0007: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000c: call ""bool System.Type.IsValueType.get"" + IL_0011: brtrue.s IL_001b + IL_0013: ldobj ""T"" + IL_0018: stloc.0 + IL_0019: ldloca.s V_0 + IL_001b: ldarga.s V_0 + IL_001d: call ""int Program.GetOffset(ref T)"" + IL_0022: constrained. ""T"" + IL_0028: callvirt ""void IMoveable.GetName(int)"" + IL_002d: ret } "); } @@ -266,23 +265,22 @@ .locals init (T V_0) verifier.VerifyIL("Program.Call2", @" { - // Code size 43 (0x2b) + // Code size 44 (0x2c) .maxstack 2 .locals init (T V_0) IL_0000: ldarg.0 - IL_0001: ldloca.s V_0 - IL_0003: initobj ""T"" - IL_0009: ldloc.0 - IL_000a: box ""T"" - IL_000f: brtrue.s IL_0019 - IL_0011: ldobj ""T"" - IL_0016: stloc.0 - IL_0017: ldloca.s V_0 - IL_0019: ldarg.0 - IL_001a: call ""int Program.GetOffset(ref T)"" - IL_001f: constrained. ""T"" - IL_0025: callvirt ""void IMoveable.GetName(int)"" - IL_002a: ret + IL_0001: ldtoken ""T"" + IL_0006: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000b: call ""bool System.Type.IsValueType.get"" + IL_0010: brtrue.s IL_001a + IL_0012: ldobj ""T"" + IL_0017: stloc.0 + IL_0018: ldloca.s V_0 + IL_001a: ldarg.0 + IL_001b: call ""int Program.GetOffset(ref T)"" + IL_0020: constrained. ""T"" + IL_0026: callvirt ""void IMoveable.GetName(int)"" + IL_002b: ret } "); } @@ -519,89 +517,86 @@ .locals init (int V_0, .maxstack 3 .locals init (int V_0, int V_1, - T V_2, - System.Runtime.CompilerServices.TaskAwaiter V_3, - System.Exception V_4) + System.Runtime.CompilerServices.TaskAwaiter V_2, + System.Exception V_3) IL_0000: ldarg.0 IL_0001: ldfld ""int Program.d__2.<>1__state"" IL_0006: stloc.0 .try { IL_0007: ldloc.0 - IL_0008: brfalse.s IL_0068 - IL_000a: ldloca.s V_2 - IL_000c: initobj ""T"" - IL_0012: ldloc.2 - IL_0013: box ""T"" - IL_0018: brtrue.s IL_0026 - IL_001a: ldarg.0 + IL_0008: brfalse.s IL_0069 + IL_000a: ldtoken ""T"" + IL_000f: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0014: call ""bool System.Type.IsValueType.get"" + IL_0019: brtrue.s IL_0027 IL_001b: ldarg.0 - IL_001c: ldfld ""T Program.d__2.item"" - IL_0021: stfld ""T Program.d__2.<>7__wrap1"" - IL_0026: ldarg.0 - IL_0027: ldflda ""T Program.d__2.item"" - IL_002c: call ""int Program.GetOffset(ref T)"" - IL_0031: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" - IL_0036: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_003b: stloc.3 - IL_003c: ldloca.s V_3 - IL_003e: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_0043: brtrue.s IL_0084 - IL_0045: ldarg.0 - IL_0046: ldc.i4.0 - IL_0047: dup - IL_0048: stloc.0 - IL_0049: stfld ""int Program.d__2.<>1__state"" - IL_004e: ldarg.0 - IL_004f: ldloc.3 - IL_0050: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_0055: ldarg.0 - IL_0056: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_005b: ldloca.s V_3 - IL_005d: ldarg.0 - IL_005e: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" - IL_0063: leave IL_00f0 - IL_0068: ldarg.0 - IL_0069: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_006e: stloc.3 - IL_006f: ldarg.0 - IL_0070: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_0075: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_007b: ldarg.0 - IL_007c: ldc.i4.m1 - IL_007d: dup - IL_007e: stloc.0 - IL_007f: stfld ""int Program.d__2.<>1__state"" - IL_0084: ldloca.s V_3 - IL_0086: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_008b: stloc.1 - IL_008c: ldloca.s V_2 - IL_008e: initobj ""T"" - IL_0094: ldloc.2 - IL_0095: box ""T"" - IL_009a: brtrue.s IL_00a4 - IL_009c: ldarg.0 - IL_009d: ldflda ""T Program.d__2.<>7__wrap1"" - IL_00a2: br.s IL_00aa - IL_00a4: ldarg.0 - IL_00a5: ldflda ""T Program.d__2.item"" - IL_00aa: ldloc.1 - IL_00ab: constrained. ""T"" - IL_00b1: callvirt ""void IMoveable.GetName(int)"" - IL_00b6: ldarg.0 - IL_00b7: ldflda ""T Program.d__2.<>7__wrap1"" - IL_00bc: initobj ""T"" - IL_00c2: leave.s IL_00dd + IL_001c: ldarg.0 + IL_001d: ldfld ""T Program.d__2.item"" + IL_0022: stfld ""T Program.d__2.<>7__wrap1"" + IL_0027: ldarg.0 + IL_0028: ldflda ""T Program.d__2.item"" + IL_002d: call ""int Program.GetOffset(ref T)"" + IL_0032: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" + IL_0037: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_003c: stloc.2 + IL_003d: ldloca.s V_2 + IL_003f: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_0044: brtrue.s IL_0085 + IL_0046: ldarg.0 + IL_0047: ldc.i4.0 + IL_0048: dup + IL_0049: stloc.0 + IL_004a: stfld ""int Program.d__2.<>1__state"" + IL_004f: ldarg.0 + IL_0050: ldloc.2 + IL_0051: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_0056: ldarg.0 + IL_0057: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_005c: ldloca.s V_2 + IL_005e: ldarg.0 + IL_005f: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" + IL_0064: leave IL_00f0 + IL_0069: ldarg.0 + IL_006a: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_006f: stloc.2 + IL_0070: ldarg.0 + IL_0071: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_0076: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_007c: ldarg.0 + IL_007d: ldc.i4.m1 + IL_007e: dup + IL_007f: stloc.0 + IL_0080: stfld ""int Program.d__2.<>1__state"" + IL_0085: ldloca.s V_2 + IL_0087: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_008c: stloc.1 + IL_008d: ldtoken ""T"" + IL_0092: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0097: call ""bool System.Type.IsValueType.get"" + IL_009c: brtrue.s IL_00a6 + IL_009e: ldarg.0 + IL_009f: ldflda ""T Program.d__2.<>7__wrap1"" + IL_00a4: br.s IL_00ac + IL_00a6: ldarg.0 + IL_00a7: ldflda ""T Program.d__2.item"" + IL_00ac: ldloc.1 + IL_00ad: constrained. ""T"" + IL_00b3: callvirt ""void IMoveable.GetName(int)"" + IL_00b8: ldarg.0 + IL_00b9: ldflda ""T Program.d__2.<>7__wrap1"" + IL_00be: initobj ""T"" + IL_00c4: leave.s IL_00dd } catch System.Exception { - IL_00c4: stloc.s V_4 - IL_00c6: ldarg.0 - IL_00c7: ldc.i4.s -2 - IL_00c9: stfld ""int Program.d__2.<>1__state"" - IL_00ce: ldarg.0 - IL_00cf: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_00d4: ldloc.s V_4 + IL_00c6: stloc.3 + IL_00c7: ldarg.0 + IL_00c8: ldc.i4.s -2 + IL_00ca: stfld ""int Program.d__2.<>1__state"" + IL_00cf: ldarg.0 + IL_00d0: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_00d5: ldloc.3 IL_00d6: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" IL_00db: leave.s IL_00f0 } @@ -967,9 +962,8 @@ .locals init (int V_0, System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter V_1, System.Runtime.CompilerServices.YieldAwaitable V_2, int V_3, - T V_4, - System.Runtime.CompilerServices.TaskAwaiter V_5, - System.Exception V_6) + System.Runtime.CompilerServices.TaskAwaiter V_4, + System.Exception V_5) IL_0000: ldarg.0 IL_0001: ldfld ""int Program.d__2.<>1__state"" IL_0006: stloc.0 @@ -1015,10 +1009,9 @@ .locals init (int V_0, IL_0062: stfld ""int Program.d__2.<>1__state"" IL_0067: ldloca.s V_1 IL_0069: call ""void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()"" - IL_006e: ldloca.s V_4 - IL_0070: initobj ""T"" - IL_0076: ldloc.s V_4 - IL_0078: box ""T"" + IL_006e: ldtoken ""T"" + IL_0073: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0078: call ""bool System.Type.IsValueType.get"" IL_007d: brtrue.s IL_008b IL_007f: ldarg.0 IL_0080: ldarg.0 @@ -1029,8 +1022,8 @@ .locals init (int V_0, IL_0091: call ""int Program.GetOffset(ref T)"" IL_0096: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" IL_009b: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_00a0: stloc.s V_5 - IL_00a2: ldloca.s V_5 + IL_00a0: stloc.s V_4 + IL_00a2: ldloca.s V_4 IL_00a4: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" IL_00a9: brtrue.s IL_00ec IL_00ab: ldarg.0 @@ -1039,17 +1032,17 @@ .locals init (int V_0, IL_00ae: stloc.0 IL_00af: stfld ""int Program.d__2.<>1__state"" IL_00b4: ldarg.0 - IL_00b5: ldloc.s V_5 + IL_00b5: ldloc.s V_4 IL_00b7: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__2"" IL_00bc: ldarg.0 IL_00bd: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_00c2: ldloca.s V_5 + IL_00c2: ldloca.s V_4 IL_00c4: ldarg.0 IL_00c5: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" IL_00ca: leave IL_0159 IL_00cf: ldarg.0 IL_00d0: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__2"" - IL_00d5: stloc.s V_5 + IL_00d5: stloc.s V_4 IL_00d7: ldarg.0 IL_00d8: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__2"" IL_00dd: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" @@ -1058,13 +1051,12 @@ .locals init (int V_0, IL_00e5: dup IL_00e6: stloc.0 IL_00e7: stfld ""int Program.d__2.<>1__state"" - IL_00ec: ldloca.s V_5 + IL_00ec: ldloca.s V_4 IL_00ee: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" IL_00f3: stloc.3 - IL_00f4: ldloca.s V_4 - IL_00f6: initobj ""T"" - IL_00fc: ldloc.s V_4 - IL_00fe: box ""T"" + IL_00f4: ldtoken ""T"" + IL_00f9: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_00fe: call ""bool System.Type.IsValueType.get"" IL_0103: brtrue.s IL_010d IL_0105: ldarg.0 IL_0106: ldflda ""T Program.d__2.<>7__wrap1"" @@ -1081,13 +1073,13 @@ .locals init (int V_0, } catch System.Exception { - IL_012d: stloc.s V_6 + IL_012d: stloc.s V_5 IL_012f: ldarg.0 IL_0130: ldc.i4.s -2 IL_0132: stfld ""int Program.d__2.<>1__state"" IL_0137: ldarg.0 IL_0138: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_013d: ldloc.s V_6 + IL_013d: ldloc.s V_5 IL_013f: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" IL_0144: leave.s IL_0159 } @@ -1408,38 +1400,36 @@ .locals init (T V_0, // Code size 86 (0x56) .maxstack 6 .locals init (T& V_0, - T V_1, - T& V_2, - T V_3, - DummyHandler V_4) + T V_1, + T& V_2, + DummyHandler V_3) IL_0000: ldarga.s V_0 IL_0002: stloc.2 - IL_0003: ldloca.s V_3 - IL_0005: initobj ""T"" - IL_000b: ldloc.3 - IL_000c: box ""T"" - IL_0011: brtrue.s IL_001e - IL_0013: ldloc.2 - IL_0014: ldobj ""T"" - IL_0019: stloc.1 - IL_001a: ldloca.s V_1 - IL_001c: br.s IL_001f - IL_001e: ldloc.2 - IL_001f: stloc.0 - IL_0020: ldloc.0 - IL_0021: ldarga.s V_0 - IL_0023: call ""int Program.GetOffset(ref T)"" - IL_0028: ldloca.s V_4 - IL_002a: ldc.i4.3 - IL_002b: ldc.i4.0 - IL_002c: ldloc.0 - IL_002d: ldobj ""T"" - IL_0032: box ""T"" - IL_0037: call ""DummyHandler..ctor(int, int, IMoveable)"" - IL_003c: ldloca.s V_4 - IL_003e: ldstr ""log"" - IL_0043: call ""void DummyHandler.AppendLiteral(string)"" - IL_0048: ldloc.s V_4 + IL_0003: ldtoken ""T"" + IL_0008: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000d: call ""bool System.Type.IsValueType.get"" + IL_0012: brtrue.s IL_001f + IL_0014: ldloc.2 + IL_0015: ldobj ""T"" + IL_001a: stloc.1 + IL_001b: ldloca.s V_1 + IL_001d: br.s IL_0020 + IL_001f: ldloc.2 + IL_0020: stloc.0 + IL_0021: ldloc.0 + IL_0022: ldarga.s V_0 + IL_0024: call ""int Program.GetOffset(ref T)"" + IL_0029: ldloca.s V_3 + IL_002b: ldc.i4.3 + IL_002c: ldc.i4.0 + IL_002d: ldloc.0 + IL_002e: ldobj ""T"" + IL_0033: box ""T"" + IL_0038: call ""DummyHandler..ctor(int, int, IMoveable)"" + IL_003d: ldloca.s V_3 + IL_003f: ldstr ""log"" + IL_0044: call ""void DummyHandler.AppendLiteral(string)"" + IL_0049: ldloc.3 IL_004a: constrained. ""T"" IL_0050: callvirt ""void IMoveable.GetName(int, DummyHandler)"" IL_0055: ret @@ -1682,38 +1672,36 @@ .locals init (T& V_0, // Code size 84 (0x54) .maxstack 6 .locals init (T& V_0, - T V_1, - T& V_2, - T V_3, - DummyHandler V_4) + T V_1, + T& V_2, + DummyHandler V_3) IL_0000: ldarg.0 IL_0001: stloc.2 - IL_0002: ldloca.s V_3 - IL_0004: initobj ""T"" - IL_000a: ldloc.3 - IL_000b: box ""T"" - IL_0010: brtrue.s IL_001d - IL_0012: ldloc.2 - IL_0013: ldobj ""T"" - IL_0018: stloc.1 - IL_0019: ldloca.s V_1 - IL_001b: br.s IL_001e - IL_001d: ldloc.2 - IL_001e: stloc.0 - IL_001f: ldloc.0 - IL_0020: ldarg.0 - IL_0021: call ""int Program.GetOffset(ref T)"" - IL_0026: ldloca.s V_4 - IL_0028: ldc.i4.3 - IL_0029: ldc.i4.0 - IL_002a: ldloc.0 - IL_002b: ldobj ""T"" - IL_0030: box ""T"" - IL_0035: call ""DummyHandler..ctor(int, int, IMoveable)"" - IL_003a: ldloca.s V_4 - IL_003c: ldstr ""log"" - IL_0041: call ""void DummyHandler.AppendLiteral(string)"" - IL_0046: ldloc.s V_4 + IL_0002: ldtoken ""T"" + IL_0007: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000c: call ""bool System.Type.IsValueType.get"" + IL_0011: brtrue.s IL_001e + IL_0013: ldloc.2 + IL_0014: ldobj ""T"" + IL_0019: stloc.1 + IL_001a: ldloca.s V_1 + IL_001c: br.s IL_001f + IL_001e: ldloc.2 + IL_001f: stloc.0 + IL_0020: ldloc.0 + IL_0021: ldarg.0 + IL_0022: call ""int Program.GetOffset(ref T)"" + IL_0027: ldloca.s V_3 + IL_0029: ldc.i4.3 + IL_002a: ldc.i4.0 + IL_002b: ldloc.0 + IL_002c: ldobj ""T"" + IL_0031: box ""T"" + IL_0036: call ""DummyHandler..ctor(int, int, IMoveable)"" + IL_003b: ldloca.s V_3 + IL_003d: ldstr ""log"" + IL_0042: call ""void DummyHandler.AppendLiteral(string)"" + IL_0047: ldloc.3 IL_0048: constrained. ""T"" IL_004e: callvirt ""void IMoveable.GetName(int, DummyHandler)"" IL_0053: ret @@ -1912,26 +1900,28 @@ .maxstack 2 verifier.VerifyIL("Program.Call2", @" { - // Code size 53 (0x35) + // Code size 55 (0x37) .maxstack 2 .locals init (T V_0) - IL_0000: ldarg.0 - IL_0001: box ""T"" - IL_0006: brfalse.s IL_0034 - IL_0008: ldarga.s V_0 - IL_000a: ldloca.s V_0 - IL_000c: initobj ""T"" - IL_0012: ldloc.0 - IL_0013: box ""T"" - IL_0018: brtrue.s IL_0022 - IL_001a: ldobj ""T"" - IL_001f: stloc.0 - IL_0020: ldloca.s V_0 - IL_0022: ldarga.s V_0 - IL_0024: call ""int Program.GetOffset(ref T)"" - IL_0029: constrained. ""T"" - IL_002f: callvirt ""void IMoveable.GetName(int)"" - IL_0034: ret + IL_0000: ldarga.s V_0 + IL_0002: ldloca.s V_0 + IL_0004: initobj ""T"" + IL_000a: ldloc.0 + IL_000b: box ""T"" + IL_0010: brtrue.s IL_0024 + IL_0012: ldobj ""T"" + IL_0017: stloc.0 + IL_0018: ldloca.s V_0 + IL_001a: ldloc.0 + IL_001b: box ""T"" + IL_0020: brtrue.s IL_0024 + IL_0022: pop + IL_0023: ret + IL_0024: ldarga.s V_0 + IL_0026: call ""int Program.GetOffset(ref T)"" + IL_002b: constrained. ""T"" + IL_0031: callvirt ""void IMoveable.GetName(int)"" + IL_0036: ret } "); } @@ -2064,10 +2054,9 @@ .maxstack 2 verifier.VerifyIL("Program.Call2", @" { - // Code size 77 (0x4d) + // Code size 53 (0x35) .maxstack 2 - .locals init (T V_0, - T V_1) + .locals init (T V_0) IL_0000: ldarg.0 IL_0001: ldloca.s V_0 IL_0003: initobj ""T"" @@ -2082,19 +2071,11 @@ .locals init (T V_0, IL_001f: brtrue.s IL_0023 IL_0021: pop IL_0022: ret - IL_0023: ldloca.s V_1 - IL_0025: initobj ""T"" - IL_002b: ldloc.1 - IL_002c: box ""T"" - IL_0031: brtrue.s IL_003b - IL_0033: ldobj ""T"" - IL_0038: stloc.1 - IL_0039: ldloca.s V_1 - IL_003b: ldarg.0 - IL_003c: call ""int Program.GetOffset(ref T)"" - IL_0041: constrained. ""T"" - IL_0047: callvirt ""void IMoveable.GetName(int)"" - IL_004c: ret + IL_0023: ldarg.0 + IL_0024: call ""int Program.GetOffset(ref T)"" + IL_0029: constrained. ""T"" + IL_002f: callvirt ""void IMoveable.GetName(int)"" + IL_0034: ret } "); } @@ -2967,30 +2948,29 @@ .locals init (T& V_0, verifier.VerifyIL("Program.Shift2", @" { - // Code size 60 (0x3c) + // Code size 61 (0x3d) .maxstack 3 .locals init (T& V_0, T V_1) IL_0000: ldarga.s V_0 IL_0002: stloc.0 IL_0003: ldloc.0 - IL_0004: ldloca.s V_1 - IL_0006: initobj ""T"" - IL_000c: ldloc.1 - IL_000d: box ""T"" - IL_0012: brtrue.s IL_001c - IL_0014: ldobj ""T"" - IL_0019: stloc.1 - IL_001a: ldloca.s V_1 - IL_001c: ldloc.0 - IL_001d: constrained. ""T"" - IL_0023: callvirt ""int IMoveable.Position.get"" - IL_0028: ldarga.s V_0 - IL_002a: call ""int Program.GetOffset(ref T)"" - IL_002f: add - IL_0030: constrained. ""T"" - IL_0036: callvirt ""void IMoveable.Position.set"" - IL_003b: ret + IL_0004: ldtoken ""T"" + IL_0009: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000e: call ""bool System.Type.IsValueType.get"" + IL_0013: brtrue.s IL_001d + IL_0015: ldobj ""T"" + IL_001a: stloc.1 + IL_001b: ldloca.s V_1 + IL_001d: ldloc.0 + IL_001e: constrained. ""T"" + IL_0024: callvirt ""int IMoveable.Position.get"" + IL_0029: ldarga.s V_0 + IL_002b: call ""int Program.GetOffset(ref T)"" + IL_0030: add + IL_0031: constrained. ""T"" + IL_0037: callvirt ""void IMoveable.Position.set"" + IL_003c: ret } "); } @@ -3176,35 +3156,34 @@ .locals init (T& V_0, verifier.VerifyIL("Program.Shift2", @" { - // Code size 58 (0x3a) + // Code size 59 (0x3b) .maxstack 3 .locals init (T& V_0, - T V_1) + T V_1) IL_0000: ldarg.0 IL_0001: stloc.0 IL_0002: ldloc.0 - IL_0003: ldloca.s V_1 - IL_0005: initobj ""T"" - IL_000b: ldloc.1 - IL_000c: box ""T"" - IL_0011: brtrue.s IL_001b - IL_0013: ldobj ""T"" - IL_0018: stloc.1 - IL_0019: ldloca.s V_1 - IL_001b: ldloc.0 - IL_001c: constrained. ""T"" - IL_0022: callvirt ""int IMoveable.Position.get"" - IL_0027: ldarg.0 - IL_0028: call ""int Program.GetOffset(ref T)"" - IL_002d: add - IL_002e: constrained. ""T"" - IL_0034: callvirt ""void IMoveable.Position.set"" - IL_0039: ret -} -"); - } - - [Fact] + IL_0003: ldtoken ""T"" + IL_0008: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000d: call ""bool System.Type.IsValueType.get"" + IL_0012: brtrue.s IL_001c + IL_0014: ldobj ""T"" + IL_0019: stloc.1 + IL_001a: ldloca.s V_1 + IL_001c: ldloc.0 + IL_001d: constrained. ""T"" + IL_0023: callvirt ""int IMoveable.Position.get"" + IL_0028: ldarg.0 + IL_0029: call ""int Program.GetOffset(ref T)"" + IL_002e: add + IL_002f: constrained. ""T"" + IL_0035: callvirt ""void IMoveable.Position.set"" + IL_003a: ret +} +"); + } + + [Fact] [WorkItem(63221, "https://github.com/dotnet/roslyn/issues/63221")] public void GenericTypeParameterAsReceiver_Assignment_Compound_Property_Struct_Ref() { @@ -3472,98 +3451,95 @@ .locals init (int V_0, .maxstack 3 .locals init (int V_0, int V_1, - T V_2, - System.Runtime.CompilerServices.TaskAwaiter V_3, - System.Exception V_4) + System.Runtime.CompilerServices.TaskAwaiter V_2, + System.Exception V_3) IL_0000: ldarg.0 IL_0001: ldfld ""int Program.d__2.<>1__state"" IL_0006: stloc.0 .try { IL_0007: ldloc.0 - IL_0008: brfalse.s IL_007f - IL_000a: ldloca.s V_2 - IL_000c: initobj ""T"" - IL_0012: ldloc.2 - IL_0013: box ""T"" - IL_0018: brtrue.s IL_0026 - IL_001a: ldarg.0 + IL_0008: brfalse.s IL_0080 + IL_000a: ldtoken ""T"" + IL_000f: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0014: call ""bool System.Type.IsValueType.get"" + IL_0019: brtrue.s IL_0027 IL_001b: ldarg.0 - IL_001c: ldfld ""T Program.d__2.item"" - IL_0021: stfld ""T Program.d__2.<>7__wrap1"" - IL_0026: ldarg.0 + IL_001c: ldarg.0 + IL_001d: ldfld ""T Program.d__2.item"" + IL_0022: stfld ""T Program.d__2.<>7__wrap1"" IL_0027: ldarg.0 - IL_0028: ldflda ""T Program.d__2.item"" - IL_002d: constrained. ""T"" - IL_0033: callvirt ""int IMoveable.Position.get"" - IL_0038: stfld ""int Program.d__2.<>7__wrap2"" - IL_003d: ldarg.0 - IL_003e: ldflda ""T Program.d__2.item"" - IL_0043: call ""int Program.GetOffset(ref T)"" - IL_0048: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" - IL_004d: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_0052: stloc.3 - IL_0053: ldloca.s V_3 - IL_0055: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_005a: brtrue.s IL_009b - IL_005c: ldarg.0 - IL_005d: ldc.i4.0 - IL_005e: dup - IL_005f: stloc.0 - IL_0060: stfld ""int Program.d__2.<>1__state"" - IL_0065: ldarg.0 - IL_0066: ldloc.3 - IL_0067: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_006c: ldarg.0 - IL_006d: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_0072: ldloca.s V_3 - IL_0074: ldarg.0 - IL_0075: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" - IL_007a: leave IL_010e - IL_007f: ldarg.0 - IL_0080: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_0085: stloc.3 - IL_0086: ldarg.0 - IL_0087: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_008c: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_0092: ldarg.0 - IL_0093: ldc.i4.m1 - IL_0094: dup - IL_0095: stloc.0 - IL_0096: stfld ""int Program.d__2.<>1__state"" - IL_009b: ldloca.s V_3 - IL_009d: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_00a2: stloc.1 - IL_00a3: ldloca.s V_2 - IL_00a5: initobj ""T"" - IL_00ab: ldloc.2 - IL_00ac: box ""T"" - IL_00b1: brtrue.s IL_00bb - IL_00b3: ldarg.0 - IL_00b4: ldflda ""T Program.d__2.<>7__wrap1"" - IL_00b9: br.s IL_00c1 - IL_00bb: ldarg.0 - IL_00bc: ldflda ""T Program.d__2.item"" - IL_00c1: ldarg.0 - IL_00c2: ldfld ""int Program.d__2.<>7__wrap2"" - IL_00c7: ldloc.1 - IL_00c8: add - IL_00c9: constrained. ""T"" - IL_00cf: callvirt ""void IMoveable.Position.set"" - IL_00d4: ldarg.0 - IL_00d5: ldflda ""T Program.d__2.<>7__wrap1"" - IL_00da: initobj ""T"" - IL_00e0: leave.s IL_00fb + IL_0028: ldarg.0 + IL_0029: ldflda ""T Program.d__2.item"" + IL_002e: constrained. ""T"" + IL_0034: callvirt ""int IMoveable.Position.get"" + IL_0039: stfld ""int Program.d__2.<>7__wrap2"" + IL_003e: ldarg.0 + IL_003f: ldflda ""T Program.d__2.item"" + IL_0044: call ""int Program.GetOffset(ref T)"" + IL_0049: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" + IL_004e: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_0053: stloc.2 + IL_0054: ldloca.s V_2 + IL_0056: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_005b: brtrue.s IL_009c + IL_005d: ldarg.0 + IL_005e: ldc.i4.0 + IL_005f: dup + IL_0060: stloc.0 + IL_0061: stfld ""int Program.d__2.<>1__state"" + IL_0066: ldarg.0 + IL_0067: ldloc.2 + IL_0068: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_006d: ldarg.0 + IL_006e: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_0073: ldloca.s V_2 + IL_0075: ldarg.0 + IL_0076: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" + IL_007b: leave IL_010e + IL_0080: ldarg.0 + IL_0081: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_0086: stloc.2 + IL_0087: ldarg.0 + IL_0088: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_008d: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_0093: ldarg.0 + IL_0094: ldc.i4.m1 + IL_0095: dup + IL_0096: stloc.0 + IL_0097: stfld ""int Program.d__2.<>1__state"" + IL_009c: ldloca.s V_2 + IL_009e: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_00a3: stloc.1 + IL_00a4: ldtoken ""T"" + IL_00a9: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_00ae: call ""bool System.Type.IsValueType.get"" + IL_00b3: brtrue.s IL_00bd + IL_00b5: ldarg.0 + IL_00b6: ldflda ""T Program.d__2.<>7__wrap1"" + IL_00bb: br.s IL_00c3 + IL_00bd: ldarg.0 + IL_00be: ldflda ""T Program.d__2.item"" + IL_00c3: ldarg.0 + IL_00c4: ldfld ""int Program.d__2.<>7__wrap2"" + IL_00c9: ldloc.1 + IL_00ca: add + IL_00cb: constrained. ""T"" + IL_00d1: callvirt ""void IMoveable.Position.set"" + IL_00d6: ldarg.0 + IL_00d7: ldflda ""T Program.d__2.<>7__wrap1"" + IL_00dc: initobj ""T"" + IL_00e2: leave.s IL_00fb } catch System.Exception { - IL_00e2: stloc.s V_4 - IL_00e4: ldarg.0 - IL_00e5: ldc.i4.s -2 - IL_00e7: stfld ""int Program.d__2.<>1__state"" - IL_00ec: ldarg.0 - IL_00ed: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_00f2: ldloc.s V_4 + IL_00e4: stloc.3 + IL_00e5: ldarg.0 + IL_00e6: ldc.i4.s -2 + IL_00e8: stfld ""int Program.d__2.<>1__state"" + IL_00ed: ldarg.0 + IL_00ee: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_00f3: ldloc.3 IL_00f4: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" IL_00f9: leave.s IL_010e } @@ -3970,9 +3946,8 @@ .locals init (int V_0, System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter V_1, System.Runtime.CompilerServices.YieldAwaitable V_2, int V_3, - T V_4, - System.Runtime.CompilerServices.TaskAwaiter V_5, - System.Exception V_6) + System.Runtime.CompilerServices.TaskAwaiter V_4, + System.Exception V_5) IL_0000: ldarg.0 IL_0001: ldfld ""int Program.d__2.<>1__state"" IL_0006: stloc.0 @@ -4018,10 +3993,9 @@ .locals init (int V_0, IL_0062: stfld ""int Program.d__2.<>1__state"" IL_0067: ldloca.s V_1 IL_0069: call ""void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()"" - IL_006e: ldloca.s V_4 - IL_0070: initobj ""T"" - IL_0076: ldloc.s V_4 - IL_0078: box ""T"" + IL_006e: ldtoken ""T"" + IL_0073: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0078: call ""bool System.Type.IsValueType.get"" IL_007d: brtrue.s IL_008b IL_007f: ldarg.0 IL_0080: ldarg.0 @@ -4038,8 +4012,8 @@ .locals init (int V_0, IL_00a8: call ""int Program.GetOffset(ref T)"" IL_00ad: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" IL_00b2: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_00b7: stloc.s V_5 - IL_00b9: ldloca.s V_5 + IL_00b7: stloc.s V_4 + IL_00b9: ldloca.s V_4 IL_00bb: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" IL_00c0: brtrue.s IL_0103 IL_00c2: ldarg.0 @@ -4048,17 +4022,17 @@ .locals init (int V_0, IL_00c5: stloc.0 IL_00c6: stfld ""int Program.d__2.<>1__state"" IL_00cb: ldarg.0 - IL_00cc: ldloc.s V_5 + IL_00cc: ldloc.s V_4 IL_00ce: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__2"" IL_00d3: ldarg.0 IL_00d4: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_00d9: ldloca.s V_5 + IL_00d9: ldloca.s V_4 IL_00db: ldarg.0 IL_00dc: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" IL_00e1: leave IL_0177 IL_00e6: ldarg.0 IL_00e7: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__2"" - IL_00ec: stloc.s V_5 + IL_00ec: stloc.s V_4 IL_00ee: ldarg.0 IL_00ef: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__2"" IL_00f4: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" @@ -4067,13 +4041,12 @@ .locals init (int V_0, IL_00fc: dup IL_00fd: stloc.0 IL_00fe: stfld ""int Program.d__2.<>1__state"" - IL_0103: ldloca.s V_5 + IL_0103: ldloca.s V_4 IL_0105: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" IL_010a: stloc.3 - IL_010b: ldloca.s V_4 - IL_010d: initobj ""T"" - IL_0113: ldloc.s V_4 - IL_0115: box ""T"" + IL_010b: ldtoken ""T"" + IL_0110: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0115: call ""bool System.Type.IsValueType.get"" IL_011a: brtrue.s IL_0124 IL_011c: ldarg.0 IL_011d: ldflda ""T Program.d__2.<>7__wrap1"" @@ -4093,13 +4066,13 @@ .locals init (int V_0, } catch System.Exception { - IL_014b: stloc.s V_6 + IL_014b: stloc.s V_5 IL_014d: ldarg.0 IL_014e: ldc.i4.s -2 IL_0150: stfld ""int Program.d__2.<>1__state"" IL_0155: ldarg.0 IL_0156: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_015b: ldloc.s V_6 + IL_015b: ldloc.s V_5 IL_015d: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" IL_0162: leave.s IL_0177 } @@ -4428,35 +4401,33 @@ .maxstack 3 .locals init (T& V_0, T V_1, T& V_2, - T V_3, - int? V_4, - int? V_5) + int? V_3, + int? V_4) IL_0000: ldarga.s V_0 IL_0002: stloc.2 - IL_0003: ldloca.s V_3 - IL_0005: initobj ""T"" - IL_000b: ldloc.3 - IL_000c: box ""T"" - IL_0011: brtrue.s IL_001e - IL_0013: ldloc.2 - IL_0014: ldobj ""T"" - IL_0019: stloc.1 - IL_001a: ldloca.s V_1 - IL_001c: br.s IL_001f - IL_001e: ldloc.2 - IL_001f: stloc.0 - IL_0020: ldloc.0 - IL_0021: constrained. ""T"" - IL_0027: callvirt ""int? IMoveable.Position.get"" - IL_002c: stloc.s V_4 - IL_002e: ldloca.s V_4 + IL_0003: ldtoken ""T"" + IL_0008: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000d: call ""bool System.Type.IsValueType.get"" + IL_0012: brtrue.s IL_001f + IL_0014: ldloc.2 + IL_0015: ldobj ""T"" + IL_001a: stloc.1 + IL_001b: ldloca.s V_1 + IL_001d: br.s IL_0020 + IL_001f: ldloc.2 + IL_0020: stloc.0 + IL_0021: ldloc.0 + IL_0022: constrained. ""T"" + IL_0028: callvirt ""int? IMoveable.Position.get"" + IL_002d: stloc.3 + IL_002e: ldloca.s V_3 IL_0030: call ""bool int?.HasValue.get"" IL_0035: brtrue.s IL_004d IL_0037: ldloc.0 IL_0038: ldarga.s V_0 IL_003a: call ""int? Program.GetOffset(ref T)"" IL_003f: dup - IL_0040: stloc.s V_5 + IL_0040: stloc.s V_4 IL_0042: constrained. ""T"" IL_0048: callvirt ""void IMoveable.Position.set"" IL_004d: ret @@ -4667,35 +4638,33 @@ .maxstack 3 .locals init (T& V_0, T V_1, T& V_2, - T V_3, - int? V_4, - int? V_5) + int? V_3, + int? V_4) IL_0000: ldarg.0 IL_0001: stloc.2 - IL_0002: ldloca.s V_3 - IL_0004: initobj ""T"" - IL_000a: ldloc.3 - IL_000b: box ""T"" - IL_0010: brtrue.s IL_001d - IL_0012: ldloc.2 - IL_0013: ldobj ""T"" - IL_0018: stloc.1 - IL_0019: ldloca.s V_1 - IL_001b: br.s IL_001e - IL_001d: ldloc.2 - IL_001e: stloc.0 - IL_001f: ldloc.0 - IL_0020: constrained. ""T"" - IL_0026: callvirt ""int? IMoveable.Position.get"" - IL_002b: stloc.s V_4 - IL_002d: ldloca.s V_4 + IL_0002: ldtoken ""T"" + IL_0007: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000c: call ""bool System.Type.IsValueType.get"" + IL_0011: brtrue.s IL_001e + IL_0013: ldloc.2 + IL_0014: ldobj ""T"" + IL_0019: stloc.1 + IL_001a: ldloca.s V_1 + IL_001c: br.s IL_001f + IL_001e: ldloc.2 + IL_001f: stloc.0 + IL_0020: ldloc.0 + IL_0021: constrained. ""T"" + IL_0027: callvirt ""int? IMoveable.Position.get"" + IL_002c: stloc.3 + IL_002d: ldloca.s V_3 IL_002f: call ""bool int?.HasValue.get"" IL_0034: brtrue.s IL_004b IL_0036: ldloc.0 IL_0037: ldarg.0 IL_0038: call ""int? Program.GetOffset(ref T)"" IL_003d: dup - IL_003e: stloc.s V_5 + IL_003e: stloc.s V_4 IL_0040: constrained. ""T"" IL_0046: callvirt ""void IMoveable.Position.set"" IL_004b: ret @@ -4983,123 +4952,119 @@ .locals init (int V_0, verifier.VerifyIL("Program.d__2.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @" { - // Code size 304 (0x130) + // Code size 306 (0x132) .maxstack 3 .locals init (int V_0, int? V_1, - T V_2, + int? V_2, int? V_3, - int? V_4, - System.Runtime.CompilerServices.TaskAwaiter V_5, - System.Exception V_6) + System.Runtime.CompilerServices.TaskAwaiter V_4, + System.Exception V_5) IL_0000: ldarg.0 IL_0001: ldfld ""int Program.d__2.<>1__state"" IL_0006: stloc.0 .try { IL_0007: ldloc.0 - IL_0008: brfalse IL_00a3 - IL_000d: ldloca.s V_2 - IL_000f: initobj ""T"" - IL_0015: ldloc.2 - IL_0016: box ""T"" - IL_001b: brtrue.s IL_0029 - IL_001d: ldarg.0 + IL_0008: brfalse IL_00a5 + IL_000d: ldtoken ""T"" + IL_0012: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0017: call ""bool System.Type.IsValueType.get"" + IL_001c: brtrue.s IL_002a IL_001e: ldarg.0 - IL_001f: ldfld ""T Program.d__2.item"" - IL_0024: stfld ""T Program.d__2.<>7__wrap1"" - IL_0029: ldloca.s V_2 - IL_002b: initobj ""T"" - IL_0031: ldloc.2 - IL_0032: box ""T"" - IL_0037: brtrue.s IL_0041 - IL_0039: ldarg.0 - IL_003a: ldflda ""T Program.d__2.<>7__wrap1"" - IL_003f: br.s IL_0047 - IL_0041: ldarg.0 - IL_0042: ldflda ""T Program.d__2.item"" - IL_0047: constrained. ""T"" - IL_004d: callvirt ""int? IMoveable.Position.get"" - IL_0052: stloc.1 - IL_0053: ldloca.s V_1 - IL_0055: call ""bool int?.HasValue.get"" - IL_005a: brtrue IL_00f5 - IL_005f: ldarg.0 - IL_0060: ldflda ""T Program.d__2.item"" - IL_0065: call ""int? Program.GetOffset(ref T)"" - IL_006a: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int?)"" - IL_006f: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_0074: stloc.s V_5 - IL_0076: ldloca.s V_5 - IL_0078: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_007d: brtrue.s IL_00c0 - IL_007f: ldarg.0 - IL_0080: ldc.i4.0 - IL_0081: dup - IL_0082: stloc.0 - IL_0083: stfld ""int Program.d__2.<>1__state"" - IL_0088: ldarg.0 - IL_0089: ldloc.s V_5 - IL_008b: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_0090: ldarg.0 - IL_0091: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_0096: ldloca.s V_5 - IL_0098: ldarg.0 - IL_0099: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" - IL_009e: leave IL_012f - IL_00a3: ldarg.0 - IL_00a4: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_00a9: stloc.s V_5 - IL_00ab: ldarg.0 - IL_00ac: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_00b1: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_00b7: ldarg.0 - IL_00b8: ldc.i4.m1 - IL_00b9: dup - IL_00ba: stloc.0 - IL_00bb: stfld ""int Program.d__2.<>1__state"" - IL_00c0: ldloca.s V_5 - IL_00c2: call ""int? System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_00c7: stloc.3 - IL_00c8: ldloca.s V_2 - IL_00ca: initobj ""T"" - IL_00d0: ldloc.2 - IL_00d1: box ""T"" - IL_00d6: brtrue.s IL_00e0 - IL_00d8: ldarg.0 - IL_00d9: ldflda ""T Program.d__2.<>7__wrap1"" - IL_00de: br.s IL_00e6 - IL_00e0: ldarg.0 - IL_00e1: ldflda ""T Program.d__2.item"" - IL_00e6: ldloc.3 - IL_00e7: dup - IL_00e8: stloc.s V_4 - IL_00ea: constrained. ""T"" - IL_00f0: callvirt ""void IMoveable.Position.set"" - IL_00f5: ldarg.0 - IL_00f6: ldflda ""T Program.d__2.<>7__wrap1"" - IL_00fb: initobj ""T"" - IL_0101: leave.s IL_011c + IL_001f: ldarg.0 + IL_0020: ldfld ""T Program.d__2.item"" + IL_0025: stfld ""T Program.d__2.<>7__wrap1"" + IL_002a: ldtoken ""T"" + IL_002f: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0034: call ""bool System.Type.IsValueType.get"" + IL_0039: brtrue.s IL_0043 + IL_003b: ldarg.0 + IL_003c: ldflda ""T Program.d__2.<>7__wrap1"" + IL_0041: br.s IL_0049 + IL_0043: ldarg.0 + IL_0044: ldflda ""T Program.d__2.item"" + IL_0049: constrained. ""T"" + IL_004f: callvirt ""int? IMoveable.Position.get"" + IL_0054: stloc.1 + IL_0055: ldloca.s V_1 + IL_0057: call ""bool int?.HasValue.get"" + IL_005c: brtrue IL_00f7 + IL_0061: ldarg.0 + IL_0062: ldflda ""T Program.d__2.item"" + IL_0067: call ""int? Program.GetOffset(ref T)"" + IL_006c: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int?)"" + IL_0071: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_0076: stloc.s V_4 + IL_0078: ldloca.s V_4 + IL_007a: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_007f: brtrue.s IL_00c2 + IL_0081: ldarg.0 + IL_0082: ldc.i4.0 + IL_0083: dup + IL_0084: stloc.0 + IL_0085: stfld ""int Program.d__2.<>1__state"" + IL_008a: ldarg.0 + IL_008b: ldloc.s V_4 + IL_008d: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_0092: ldarg.0 + IL_0093: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_0098: ldloca.s V_4 + IL_009a: ldarg.0 + IL_009b: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" + IL_00a0: leave IL_0131 + IL_00a5: ldarg.0 + IL_00a6: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_00ab: stloc.s V_4 + IL_00ad: ldarg.0 + IL_00ae: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_00b3: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_00b9: ldarg.0 + IL_00ba: ldc.i4.m1 + IL_00bb: dup + IL_00bc: stloc.0 + IL_00bd: stfld ""int Program.d__2.<>1__state"" + IL_00c2: ldloca.s V_4 + IL_00c4: call ""int? System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_00c9: stloc.2 + IL_00ca: ldtoken ""T"" + IL_00cf: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_00d4: call ""bool System.Type.IsValueType.get"" + IL_00d9: brtrue.s IL_00e3 + IL_00db: ldarg.0 + IL_00dc: ldflda ""T Program.d__2.<>7__wrap1"" + IL_00e1: br.s IL_00e9 + IL_00e3: ldarg.0 + IL_00e4: ldflda ""T Program.d__2.item"" + IL_00e9: ldloc.2 + IL_00ea: dup + IL_00eb: stloc.3 + IL_00ec: constrained. ""T"" + IL_00f2: callvirt ""void IMoveable.Position.set"" + IL_00f7: ldarg.0 + IL_00f8: ldflda ""T Program.d__2.<>7__wrap1"" + IL_00fd: initobj ""T"" + IL_0103: leave.s IL_011e } catch System.Exception { - IL_0103: stloc.s V_6 - IL_0105: ldarg.0 - IL_0106: ldc.i4.s -2 - IL_0108: stfld ""int Program.d__2.<>1__state"" - IL_010d: ldarg.0 - IL_010e: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_0113: ldloc.s V_6 - IL_0115: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" - IL_011a: leave.s IL_012f + IL_0105: stloc.s V_5 + IL_0107: ldarg.0 + IL_0108: ldc.i4.s -2 + IL_010a: stfld ""int Program.d__2.<>1__state"" + IL_010f: ldarg.0 + IL_0110: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_0115: ldloc.s V_5 + IL_0117: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" + IL_011c: leave.s IL_0131 } - IL_011c: ldarg.0 - IL_011d: ldc.i4.s -2 - IL_011f: stfld ""int Program.d__2.<>1__state"" - IL_0124: ldarg.0 - IL_0125: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_012a: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" - IL_012f: ret + IL_011e: ldarg.0 + IL_011f: ldc.i4.s -2 + IL_0121: stfld ""int Program.d__2.<>1__state"" + IL_0126: ldarg.0 + IL_0127: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_012c: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" + IL_0131: ret } "); } @@ -5505,11 +5470,10 @@ .locals init (int V_0, System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter V_1, System.Runtime.CompilerServices.YieldAwaitable V_2, int? V_3, - T V_4, + int? V_4, int? V_5, - int? V_6, - System.Runtime.CompilerServices.TaskAwaiter V_7, - System.Exception V_8) + System.Runtime.CompilerServices.TaskAwaiter V_6, + System.Exception V_7) IL_0000: ldarg.0 IL_0001: ldfld ""int Program.d__2.<>1__state"" IL_0006: stloc.0 @@ -5555,19 +5519,17 @@ .locals init (int V_0, IL_0062: stfld ""int Program.d__2.<>1__state"" IL_0067: ldloca.s V_1 IL_0069: call ""void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()"" - IL_006e: ldloca.s V_4 - IL_0070: initobj ""T"" - IL_0076: ldloc.s V_4 - IL_0078: box ""T"" + IL_006e: ldtoken ""T"" + IL_0073: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0078: call ""bool System.Type.IsValueType.get"" IL_007d: brtrue.s IL_008b IL_007f: ldarg.0 IL_0080: ldarg.0 IL_0081: ldfld ""T Program.d__2.item"" IL_0086: stfld ""T Program.d__2.<>7__wrap1"" - IL_008b: ldloca.s V_4 - IL_008d: initobj ""T"" - IL_0093: ldloc.s V_4 - IL_0095: box ""T"" + IL_008b: ldtoken ""T"" + IL_0090: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0095: call ""bool System.Type.IsValueType.get"" IL_009a: brtrue.s IL_00a4 IL_009c: ldarg.0 IL_009d: ldflda ""T Program.d__2.<>7__wrap1"" @@ -5585,8 +5547,8 @@ .locals init (int V_0, IL_00c8: call ""int? Program.GetOffset(ref T)"" IL_00cd: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int?)"" IL_00d2: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_00d7: stloc.s V_7 - IL_00d9: ldloca.s V_7 + IL_00d7: stloc.s V_6 + IL_00d9: ldloca.s V_6 IL_00db: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" IL_00e0: brtrue.s IL_0123 IL_00e2: ldarg.0 @@ -5595,17 +5557,17 @@ .locals init (int V_0, IL_00e5: stloc.0 IL_00e6: stfld ""int Program.d__2.<>1__state"" IL_00eb: ldarg.0 - IL_00ec: ldloc.s V_7 + IL_00ec: ldloc.s V_6 IL_00ee: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__2"" IL_00f3: ldarg.0 IL_00f4: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_00f9: ldloca.s V_7 + IL_00f9: ldloca.s V_6 IL_00fb: ldarg.0 IL_00fc: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" IL_0101: leave IL_0195 IL_0106: ldarg.0 IL_0107: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__2"" - IL_010c: stloc.s V_7 + IL_010c: stloc.s V_6 IL_010e: ldarg.0 IL_010f: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__2"" IL_0114: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" @@ -5614,22 +5576,21 @@ .locals init (int V_0, IL_011c: dup IL_011d: stloc.0 IL_011e: stfld ""int Program.d__2.<>1__state"" - IL_0123: ldloca.s V_7 + IL_0123: ldloca.s V_6 IL_0125: call ""int? System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_012a: stloc.s V_5 - IL_012c: ldloca.s V_4 - IL_012e: initobj ""T"" - IL_0134: ldloc.s V_4 - IL_0136: box ""T"" + IL_012a: stloc.s V_4 + IL_012c: ldtoken ""T"" + IL_0131: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0136: call ""bool System.Type.IsValueType.get"" IL_013b: brtrue.s IL_0145 IL_013d: ldarg.0 IL_013e: ldflda ""T Program.d__2.<>7__wrap1"" IL_0143: br.s IL_014b IL_0145: ldarg.0 IL_0146: ldflda ""T Program.d__2.item"" - IL_014b: ldloc.s V_5 + IL_014b: ldloc.s V_4 IL_014d: dup - IL_014e: stloc.s V_6 + IL_014e: stloc.s V_5 IL_0150: constrained. ""T"" IL_0156: callvirt ""void IMoveable.Position.set"" IL_015b: ldarg.0 @@ -5639,13 +5600,13 @@ .locals init (int V_0, } catch System.Exception { - IL_0169: stloc.s V_8 + IL_0169: stloc.s V_7 IL_016b: ldarg.0 IL_016c: ldc.i4.s -2 IL_016e: stfld ""int Program.d__2.<>1__state"" IL_0173: ldarg.0 IL_0174: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_0179: ldloc.s V_8 + IL_0179: ldloc.s V_7 IL_017b: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" IL_0180: leave.s IL_0195 } @@ -5975,14 +5936,12 @@ .maxstack 4 .locals init (T& V_0, T V_1, T& V_2, - int V_3, - T V_4) + int V_3) IL_0000: ldarga.s V_0 IL_0002: stloc.2 - IL_0003: ldloca.s V_4 - IL_0005: initobj ""T"" - IL_000b: ldloc.s V_4 - IL_000d: box ""T"" + IL_0003: ldtoken ""T"" + IL_0008: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000d: call ""bool System.Type.IsValueType.get"" IL_0012: brtrue.s IL_001f IL_0014: ldloc.2 IL_0015: ldobj ""T"" @@ -6208,14 +6167,12 @@ .maxstack 4 .locals init (T& V_0, T V_1, T& V_2, - int V_3, - T V_4) + int V_3) IL_0000: ldarg.0 IL_0001: stloc.2 - IL_0002: ldloca.s V_4 - IL_0004: initobj ""T"" - IL_000a: ldloc.s V_4 - IL_000c: box ""T"" + IL_0002: ldtoken ""T"" + IL_0007: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000c: call ""bool System.Type.IsValueType.get"" IL_0011: brtrue.s IL_001e IL_0013: ldloc.2 IL_0014: ldobj ""T"" @@ -6509,118 +6466,114 @@ .locals init (int V_0, verifier.VerifyIL("Program.d__2.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @" { - // Code size 285 (0x11d) + // Code size 286 (0x11e) .maxstack 4 .locals init (int V_0, int V_1, - T V_2, - System.Runtime.CompilerServices.TaskAwaiter V_3, - System.Exception V_4) + System.Runtime.CompilerServices.TaskAwaiter V_2, + System.Exception V_3) IL_0000: ldarg.0 IL_0001: ldfld ""int Program.d__2.<>1__state"" IL_0006: stloc.0 .try { IL_0007: ldloc.0 - IL_0008: brfalse.s IL_0068 - IL_000a: ldloca.s V_2 - IL_000c: initobj ""T"" - IL_0012: ldloc.2 - IL_0013: box ""T"" - IL_0018: brtrue.s IL_0026 - IL_001a: ldarg.0 + IL_0008: brfalse.s IL_0069 + IL_000a: ldtoken ""T"" + IL_000f: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0014: call ""bool System.Type.IsValueType.get"" + IL_0019: brtrue.s IL_0027 IL_001b: ldarg.0 - IL_001c: ldfld ""T Program.d__2.item"" - IL_0021: stfld ""T Program.d__2.<>7__wrap1"" - IL_0026: ldarg.0 - IL_0027: ldflda ""T Program.d__2.item"" - IL_002c: call ""int Program.GetOffset(ref T)"" - IL_0031: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" - IL_0036: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_003b: stloc.3 - IL_003c: ldloca.s V_3 - IL_003e: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_0043: brtrue.s IL_0084 - IL_0045: ldarg.0 - IL_0046: ldc.i4.0 - IL_0047: dup - IL_0048: stloc.0 - IL_0049: stfld ""int Program.d__2.<>1__state"" - IL_004e: ldarg.0 - IL_004f: ldloc.3 - IL_0050: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_0055: ldarg.0 - IL_0056: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_005b: ldloca.s V_3 - IL_005d: ldarg.0 - IL_005e: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" - IL_0063: leave IL_011c - IL_0068: ldarg.0 - IL_0069: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_006e: stloc.3 - IL_006f: ldarg.0 - IL_0070: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_0075: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_007b: ldarg.0 - IL_007c: ldc.i4.m1 - IL_007d: dup - IL_007e: stloc.0 - IL_007f: stfld ""int Program.d__2.<>1__state"" - IL_0084: ldloca.s V_3 - IL_0086: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_008b: stloc.1 - IL_008c: ldloca.s V_2 - IL_008e: initobj ""T"" - IL_0094: ldloc.2 - IL_0095: box ""T"" - IL_009a: brtrue.s IL_00a4 - IL_009c: ldarg.0 - IL_009d: ldflda ""T Program.d__2.<>7__wrap1"" - IL_00a2: br.s IL_00aa - IL_00a4: ldarg.0 - IL_00a5: ldflda ""T Program.d__2.item"" - IL_00aa: ldloc.1 - IL_00ab: ldloca.s V_2 - IL_00ad: initobj ""T"" - IL_00b3: ldloc.2 - IL_00b4: box ""T"" - IL_00b9: brtrue.s IL_00c3 - IL_00bb: ldarg.0 - IL_00bc: ldflda ""T Program.d__2.<>7__wrap1"" - IL_00c1: br.s IL_00c9 - IL_00c3: ldarg.0 - IL_00c4: ldflda ""T Program.d__2.item"" - IL_00c9: ldloc.1 - IL_00ca: constrained. ""T"" - IL_00d0: callvirt ""int IMoveable.this[int].get"" - IL_00d5: ldc.i4.1 - IL_00d6: add - IL_00d7: constrained. ""T"" - IL_00dd: callvirt ""void IMoveable.this[int].set"" - IL_00e2: ldarg.0 - IL_00e3: ldflda ""T Program.d__2.<>7__wrap1"" - IL_00e8: initobj ""T"" - IL_00ee: leave.s IL_0109 + IL_001c: ldarg.0 + IL_001d: ldfld ""T Program.d__2.item"" + IL_0022: stfld ""T Program.d__2.<>7__wrap1"" + IL_0027: ldarg.0 + IL_0028: ldflda ""T Program.d__2.item"" + IL_002d: call ""int Program.GetOffset(ref T)"" + IL_0032: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" + IL_0037: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_003c: stloc.2 + IL_003d: ldloca.s V_2 + IL_003f: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_0044: brtrue.s IL_0085 + IL_0046: ldarg.0 + IL_0047: ldc.i4.0 + IL_0048: dup + IL_0049: stloc.0 + IL_004a: stfld ""int Program.d__2.<>1__state"" + IL_004f: ldarg.0 + IL_0050: ldloc.2 + IL_0051: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_0056: ldarg.0 + IL_0057: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_005c: ldloca.s V_2 + IL_005e: ldarg.0 + IL_005f: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" + IL_0064: leave IL_011d + IL_0069: ldarg.0 + IL_006a: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_006f: stloc.2 + IL_0070: ldarg.0 + IL_0071: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_0076: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_007c: ldarg.0 + IL_007d: ldc.i4.m1 + IL_007e: dup + IL_007f: stloc.0 + IL_0080: stfld ""int Program.d__2.<>1__state"" + IL_0085: ldloca.s V_2 + IL_0087: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_008c: stloc.1 + IL_008d: ldtoken ""T"" + IL_0092: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0097: call ""bool System.Type.IsValueType.get"" + IL_009c: brtrue.s IL_00a6 + IL_009e: ldarg.0 + IL_009f: ldflda ""T Program.d__2.<>7__wrap1"" + IL_00a4: br.s IL_00ac + IL_00a6: ldarg.0 + IL_00a7: ldflda ""T Program.d__2.item"" + IL_00ac: ldloc.1 + IL_00ad: ldtoken ""T"" + IL_00b2: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_00b7: call ""bool System.Type.IsValueType.get"" + IL_00bc: brtrue.s IL_00c6 + IL_00be: ldarg.0 + IL_00bf: ldflda ""T Program.d__2.<>7__wrap1"" + IL_00c4: br.s IL_00cc + IL_00c6: ldarg.0 + IL_00c7: ldflda ""T Program.d__2.item"" + IL_00cc: ldloc.1 + IL_00cd: constrained. ""T"" + IL_00d3: callvirt ""int IMoveable.this[int].get"" + IL_00d8: ldc.i4.1 + IL_00d9: add + IL_00da: constrained. ""T"" + IL_00e0: callvirt ""void IMoveable.this[int].set"" + IL_00e5: ldarg.0 + IL_00e6: ldflda ""T Program.d__2.<>7__wrap1"" + IL_00eb: initobj ""T"" + IL_00f1: leave.s IL_010a } catch System.Exception { - IL_00f0: stloc.s V_4 - IL_00f2: ldarg.0 - IL_00f3: ldc.i4.s -2 - IL_00f5: stfld ""int Program.d__2.<>1__state"" - IL_00fa: ldarg.0 - IL_00fb: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_0100: ldloc.s V_4 - IL_0102: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" - IL_0107: leave.s IL_011c + IL_00f3: stloc.3 + IL_00f4: ldarg.0 + IL_00f5: ldc.i4.s -2 + IL_00f7: stfld ""int Program.d__2.<>1__state"" + IL_00fc: ldarg.0 + IL_00fd: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_0102: ldloc.3 + IL_0103: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" + IL_0108: leave.s IL_011d } - IL_0109: ldarg.0 - IL_010a: ldc.i4.s -2 - IL_010c: stfld ""int Program.d__2.<>1__state"" - IL_0111: ldarg.0 - IL_0112: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_0117: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" - IL_011c: ret + IL_010a: ldarg.0 + IL_010b: ldc.i4.s -2 + IL_010d: stfld ""int Program.d__2.<>1__state"" + IL_0112: ldarg.0 + IL_0113: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_0118: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" + IL_011d: ret } "); } @@ -7010,9 +6963,8 @@ .locals init (int V_0, System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter V_1, System.Runtime.CompilerServices.YieldAwaitable V_2, int V_3, - T V_4, - System.Runtime.CompilerServices.TaskAwaiter V_5, - System.Exception V_6) + System.Runtime.CompilerServices.TaskAwaiter V_4, + System.Exception V_5) IL_0000: ldarg.0 IL_0001: ldfld ""int Program.d__2.<>1__state"" IL_0006: stloc.0 @@ -7058,10 +7010,9 @@ .locals init (int V_0, IL_0062: stfld ""int Program.d__2.<>1__state"" IL_0067: ldloca.s V_1 IL_0069: call ""void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()"" - IL_006e: ldloca.s V_4 - IL_0070: initobj ""T"" - IL_0076: ldloc.s V_4 - IL_0078: box ""T"" + IL_006e: ldtoken ""T"" + IL_0073: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0078: call ""bool System.Type.IsValueType.get"" IL_007d: brtrue.s IL_008b IL_007f: ldarg.0 IL_0080: ldarg.0 @@ -7072,8 +7023,8 @@ .locals init (int V_0, IL_0091: call ""int Program.GetOffset(ref T)"" IL_0096: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" IL_009b: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_00a0: stloc.s V_5 - IL_00a2: ldloca.s V_5 + IL_00a0: stloc.s V_4 + IL_00a2: ldloca.s V_4 IL_00a4: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" IL_00a9: brtrue.s IL_00ec IL_00ab: ldarg.0 @@ -7082,17 +7033,17 @@ .locals init (int V_0, IL_00ae: stloc.0 IL_00af: stfld ""int Program.d__2.<>1__state"" IL_00b4: ldarg.0 - IL_00b5: ldloc.s V_5 + IL_00b5: ldloc.s V_4 IL_00b7: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__2"" IL_00bc: ldarg.0 IL_00bd: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_00c2: ldloca.s V_5 + IL_00c2: ldloca.s V_4 IL_00c4: ldarg.0 IL_00c5: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" IL_00ca: leave IL_0186 IL_00cf: ldarg.0 IL_00d0: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__2"" - IL_00d5: stloc.s V_5 + IL_00d5: stloc.s V_4 IL_00d7: ldarg.0 IL_00d8: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__2"" IL_00dd: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" @@ -7101,13 +7052,12 @@ .locals init (int V_0, IL_00e5: dup IL_00e6: stloc.0 IL_00e7: stfld ""int Program.d__2.<>1__state"" - IL_00ec: ldloca.s V_5 + IL_00ec: ldloca.s V_4 IL_00ee: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" IL_00f3: stloc.3 - IL_00f4: ldloca.s V_4 - IL_00f6: initobj ""T"" - IL_00fc: ldloc.s V_4 - IL_00fe: box ""T"" + IL_00f4: ldtoken ""T"" + IL_00f9: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_00fe: call ""bool System.Type.IsValueType.get"" IL_0103: brtrue.s IL_010d IL_0105: ldarg.0 IL_0106: ldflda ""T Program.d__2.<>7__wrap1"" @@ -7115,10 +7065,9 @@ .locals init (int V_0, IL_010d: ldarg.0 IL_010e: ldflda ""T Program.d__2.item"" IL_0113: ldloc.3 - IL_0114: ldloca.s V_4 - IL_0116: initobj ""T"" - IL_011c: ldloc.s V_4 - IL_011e: box ""T"" + IL_0114: ldtoken ""T"" + IL_0119: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_011e: call ""bool System.Type.IsValueType.get"" IL_0123: brtrue.s IL_012d IL_0125: ldarg.0 IL_0126: ldflda ""T Program.d__2.<>7__wrap1"" @@ -7139,13 +7088,13 @@ .locals init (int V_0, } catch System.Exception { - IL_015a: stloc.s V_6 + IL_015a: stloc.s V_5 IL_015c: ldarg.0 IL_015d: ldc.i4.s -2 IL_015f: stfld ""int Program.d__2.<>1__state"" IL_0164: ldarg.0 IL_0165: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_016a: ldloc.s V_6 + IL_016a: ldloc.s V_5 IL_016c: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" IL_0171: leave.s IL_0186 } @@ -7470,14 +7419,12 @@ .maxstack 4 .locals init (T V_0, T& V_1, int V_2, - int V_3, - T V_4) + int V_3) IL_0000: ldarga.s V_0 IL_0002: stloc.1 - IL_0003: ldloca.s V_4 - IL_0005: initobj ""T"" - IL_000b: ldloc.s V_4 - IL_000d: box ""T"" + IL_0003: ldtoken ""T"" + IL_0008: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000d: call ""bool System.Type.IsValueType.get"" IL_0012: brtrue.s IL_001f IL_0014: ldloc.1 IL_0015: ldobj ""T"" @@ -7703,14 +7650,12 @@ .maxstack 4 .locals init (T V_0, T& V_1, int V_2, - int V_3, - T V_4) + int V_3) IL_0000: ldarg.0 IL_0001: stloc.1 - IL_0002: ldloca.s V_4 - IL_0004: initobj ""T"" - IL_000a: ldloc.s V_4 - IL_000c: box ""T"" + IL_0002: ldtoken ""T"" + IL_0007: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000c: call ""bool System.Type.IsValueType.get"" IL_0011: brtrue.s IL_001e IL_0013: ldloc.1 IL_0014: ldobj ""T"" @@ -8012,80 +7957,76 @@ .maxstack 4 .locals init (int V_0, int V_1, int V_2, - T V_3, - System.Runtime.CompilerServices.TaskAwaiter V_4, - System.Exception V_5) + System.Runtime.CompilerServices.TaskAwaiter V_3, + System.Exception V_4) IL_0000: ldarg.0 IL_0001: ldfld ""int Program.d__2.<>1__state"" IL_0006: stloc.0 .try { IL_0007: ldloc.0 - IL_0008: brfalse.s IL_006a - IL_000a: ldloca.s V_3 - IL_000c: initobj ""T"" - IL_0012: ldloc.3 - IL_0013: box ""T"" - IL_0018: brtrue.s IL_0026 - IL_001a: ldarg.0 + IL_0008: brfalse.s IL_0069 + IL_000a: ldtoken ""T"" + IL_000f: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0014: call ""bool System.Type.IsValueType.get"" + IL_0019: brtrue.s IL_0027 IL_001b: ldarg.0 - IL_001c: ldfld ""T Program.d__2.item"" - IL_0021: stfld ""T Program.d__2.<>7__wrap1"" - IL_0026: ldarg.0 - IL_0027: ldflda ""T Program.d__2.item"" - IL_002c: call ""int Program.GetOffset(ref T)"" - IL_0031: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" - IL_0036: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_003b: stloc.s V_4 - IL_003d: ldloca.s V_4 + IL_001c: ldarg.0 + IL_001d: ldfld ""T Program.d__2.item"" + IL_0022: stfld ""T Program.d__2.<>7__wrap1"" + IL_0027: ldarg.0 + IL_0028: ldflda ""T Program.d__2.item"" + IL_002d: call ""int Program.GetOffset(ref T)"" + IL_0032: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" + IL_0037: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_003c: stloc.3 + IL_003d: ldloca.s V_3 IL_003f: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_0044: brtrue.s IL_0087 + IL_0044: brtrue.s IL_0085 IL_0046: ldarg.0 IL_0047: ldc.i4.0 IL_0048: dup IL_0049: stloc.0 IL_004a: stfld ""int Program.d__2.<>1__state"" IL_004f: ldarg.0 - IL_0050: ldloc.s V_4 - IL_0052: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_0057: ldarg.0 - IL_0058: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_005d: ldloca.s V_4 - IL_005f: ldarg.0 - IL_0060: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" - IL_0065: leave IL_0121 - IL_006a: ldarg.0 - IL_006b: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_0070: stloc.s V_4 - IL_0072: ldarg.0 - IL_0073: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_0078: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_007e: ldarg.0 - IL_007f: ldc.i4.m1 - IL_0080: dup - IL_0081: stloc.0 - IL_0082: stfld ""int Program.d__2.<>1__state"" - IL_0087: ldloca.s V_4 - IL_0089: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_008e: stloc.1 - IL_008f: ldloca.s V_3 - IL_0091: initobj ""T"" - IL_0097: ldloc.3 - IL_0098: box ""T"" - IL_009d: brtrue.s IL_00a7 - IL_009f: ldarg.0 - IL_00a0: ldflda ""T Program.d__2.<>7__wrap1"" - IL_00a5: br.s IL_00ad - IL_00a7: ldarg.0 - IL_00a8: ldflda ""T Program.d__2.item"" - IL_00ad: ldloc.1 - IL_00ae: constrained. ""T"" - IL_00b4: callvirt ""int IMoveable.this[int].get"" - IL_00b9: stloc.2 - IL_00ba: ldloca.s V_3 - IL_00bc: initobj ""T"" - IL_00c2: ldloc.3 - IL_00c3: box ""T"" + IL_0050: ldloc.3 + IL_0051: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_0056: ldarg.0 + IL_0057: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_005c: ldloca.s V_3 + IL_005e: ldarg.0 + IL_005f: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" + IL_0064: leave IL_0121 + IL_0069: ldarg.0 + IL_006a: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_006f: stloc.3 + IL_0070: ldarg.0 + IL_0071: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_0076: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_007c: ldarg.0 + IL_007d: ldc.i4.m1 + IL_007e: dup + IL_007f: stloc.0 + IL_0080: stfld ""int Program.d__2.<>1__state"" + IL_0085: ldloca.s V_3 + IL_0087: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_008c: stloc.1 + IL_008d: ldtoken ""T"" + IL_0092: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0097: call ""bool System.Type.IsValueType.get"" + IL_009c: brtrue.s IL_00a6 + IL_009e: ldarg.0 + IL_009f: ldflda ""T Program.d__2.<>7__wrap1"" + IL_00a4: br.s IL_00ac + IL_00a6: ldarg.0 + IL_00a7: ldflda ""T Program.d__2.item"" + IL_00ac: ldloc.1 + IL_00ad: constrained. ""T"" + IL_00b3: callvirt ""int IMoveable.this[int].get"" + IL_00b8: stloc.2 + IL_00b9: ldtoken ""T"" + IL_00be: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_00c3: call ""bool System.Type.IsValueType.get"" IL_00c8: brtrue.s IL_00d2 IL_00ca: ldarg.0 IL_00cb: ldflda ""T Program.d__2.<>7__wrap1"" @@ -8105,13 +8046,13 @@ .locals init (int V_0, } catch System.Exception { - IL_00f5: stloc.s V_5 + IL_00f5: stloc.s V_4 IL_00f7: ldarg.0 IL_00f8: ldc.i4.s -2 IL_00fa: stfld ""int Program.d__2.<>1__state"" IL_00ff: ldarg.0 IL_0100: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_0105: ldloc.s V_5 + IL_0105: ldloc.s V_4 IL_0107: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" IL_010c: leave.s IL_0121 } @@ -8518,9 +8459,8 @@ .locals init (int V_0, System.Runtime.CompilerServices.YieldAwaitable V_2, int V_3, int V_4, - T V_5, - System.Runtime.CompilerServices.TaskAwaiter V_6, - System.Exception V_7) + System.Runtime.CompilerServices.TaskAwaiter V_5, + System.Exception V_6) IL_0000: ldarg.0 IL_0001: ldfld ""int Program.d__2.<>1__state"" IL_0006: stloc.0 @@ -8566,10 +8506,9 @@ .locals init (int V_0, IL_0062: stfld ""int Program.d__2.<>1__state"" IL_0067: ldloca.s V_1 IL_0069: call ""void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()"" - IL_006e: ldloca.s V_5 - IL_0070: initobj ""T"" - IL_0076: ldloc.s V_5 - IL_0078: box ""T"" + IL_006e: ldtoken ""T"" + IL_0073: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0078: call ""bool System.Type.IsValueType.get"" IL_007d: brtrue.s IL_008b IL_007f: ldarg.0 IL_0080: ldarg.0 @@ -8580,8 +8519,8 @@ .locals init (int V_0, IL_0091: call ""int Program.GetOffset(ref T)"" IL_0096: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" IL_009b: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_00a0: stloc.s V_6 - IL_00a2: ldloca.s V_6 + IL_00a0: stloc.s V_5 + IL_00a2: ldloca.s V_5 IL_00a4: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" IL_00a9: brtrue.s IL_00ec IL_00ab: ldarg.0 @@ -8590,17 +8529,17 @@ .locals init (int V_0, IL_00ae: stloc.0 IL_00af: stfld ""int Program.d__2.<>1__state"" IL_00b4: ldarg.0 - IL_00b5: ldloc.s V_6 + IL_00b5: ldloc.s V_5 IL_00b7: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__2"" IL_00bc: ldarg.0 IL_00bd: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_00c2: ldloca.s V_6 + IL_00c2: ldloca.s V_5 IL_00c4: ldarg.0 IL_00c5: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" IL_00ca: leave IL_018a IL_00cf: ldarg.0 IL_00d0: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__2"" - IL_00d5: stloc.s V_6 + IL_00d5: stloc.s V_5 IL_00d7: ldarg.0 IL_00d8: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__2"" IL_00dd: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" @@ -8609,13 +8548,12 @@ .locals init (int V_0, IL_00e5: dup IL_00e6: stloc.0 IL_00e7: stfld ""int Program.d__2.<>1__state"" - IL_00ec: ldloca.s V_6 + IL_00ec: ldloca.s V_5 IL_00ee: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" IL_00f3: stloc.3 - IL_00f4: ldloca.s V_5 - IL_00f6: initobj ""T"" - IL_00fc: ldloc.s V_5 - IL_00fe: box ""T"" + IL_00f4: ldtoken ""T"" + IL_00f9: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_00fe: call ""bool System.Type.IsValueType.get"" IL_0103: brtrue.s IL_010d IL_0105: ldarg.0 IL_0106: ldflda ""T Program.d__2.<>7__wrap1"" @@ -8626,10 +8564,9 @@ .locals init (int V_0, IL_0114: constrained. ""T"" IL_011a: callvirt ""int IMoveable.this[int].get"" IL_011f: stloc.s V_4 - IL_0121: ldloca.s V_5 - IL_0123: initobj ""T"" - IL_0129: ldloc.s V_5 - IL_012b: box ""T"" + IL_0121: ldtoken ""T"" + IL_0126: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_012b: call ""bool System.Type.IsValueType.get"" IL_0130: brtrue.s IL_013a IL_0132: ldarg.0 IL_0133: ldflda ""T Program.d__2.<>7__wrap1"" @@ -8649,13 +8586,13 @@ .locals init (int V_0, } catch System.Exception { - IL_015e: stloc.s V_7 + IL_015e: stloc.s V_6 IL_0160: ldarg.0 IL_0161: ldc.i4.s -2 IL_0163: stfld ""int Program.d__2.<>1__state"" IL_0168: ldarg.0 IL_0169: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_016e: ldloc.s V_7 + IL_016e: ldloc.s V_6 IL_0170: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" IL_0175: leave.s IL_018a } @@ -9000,14 +8937,12 @@ .locals init (T& V_0, int V_3, int? V_4, int V_5, - T V_6, - int? V_7) + int? V_6) IL_0000: ldarga.s V_0 IL_0002: stloc.2 - IL_0003: ldloca.s V_6 - IL_0005: initobj ""T"" - IL_000b: ldloc.s V_6 - IL_000d: box ""T"" + IL_0003: ldtoken ""T"" + IL_0008: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000d: call ""bool System.Type.IsValueType.get"" IL_0012: brtrue.s IL_001f IL_0014: ldloc.2 IL_0015: ldobj ""T"" @@ -9034,10 +8969,10 @@ .locals init (T& V_0, IL_004b: stloc.s V_5 IL_004d: ldloc.0 IL_004e: ldloc.3 - IL_004f: ldloca.s V_7 + IL_004f: ldloca.s V_6 IL_0051: ldloc.s V_5 IL_0053: call ""int?..ctor(int)"" - IL_0058: ldloc.s V_7 + IL_0058: ldloc.s V_6 IL_005a: constrained. ""T"" IL_0060: callvirt ""void IMoveable.this[int].set"" IL_0065: ret @@ -9275,14 +9210,12 @@ .locals init (T& V_0, int V_3, int? V_4, int V_5, - T V_6, - int? V_7) + int? V_6) IL_0000: ldarg.0 IL_0001: stloc.2 - IL_0002: ldloca.s V_6 - IL_0004: initobj ""T"" - IL_000a: ldloc.s V_6 - IL_000c: box ""T"" + IL_0002: ldtoken ""T"" + IL_0007: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000c: call ""bool System.Type.IsValueType.get"" IL_0011: brtrue.s IL_001e IL_0013: ldloc.2 IL_0014: ldobj ""T"" @@ -9309,10 +9242,10 @@ .locals init (T& V_0, IL_0049: stloc.s V_5 IL_004b: ldloc.0 IL_004c: ldloc.3 - IL_004d: ldloca.s V_7 + IL_004d: ldloca.s V_6 IL_004f: ldloc.s V_5 IL_0051: call ""int?..ctor(int)"" - IL_0056: ldloc.s V_7 + IL_0056: ldloc.s V_6 IL_0058: constrained. ""T"" IL_005e: callvirt ""void IMoveable.this[int].set"" IL_0063: ret @@ -9621,10 +9554,9 @@ .locals init (int V_0, int V_1, int? V_2, int V_3, - T V_4, - System.Runtime.CompilerServices.TaskAwaiter V_5, - int? V_6, - System.Exception V_7) + System.Runtime.CompilerServices.TaskAwaiter V_4, + int? V_5, + System.Exception V_6) IL_0000: ldarg.0 IL_0001: ldfld ""int Program.d__2.<>1__state"" IL_0006: stloc.0 @@ -9632,10 +9564,9 @@ .locals init (int V_0, { IL_0007: ldloc.0 IL_0008: brfalse.s IL_006b - IL_000a: ldloca.s V_4 - IL_000c: initobj ""T"" - IL_0012: ldloc.s V_4 - IL_0014: box ""T"" + IL_000a: ldtoken ""T"" + IL_000f: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0014: call ""bool System.Type.IsValueType.get"" IL_0019: brtrue.s IL_0027 IL_001b: ldarg.0 IL_001c: ldarg.0 @@ -9646,8 +9577,8 @@ .locals init (int V_0, IL_002d: call ""int Program.GetOffset(ref T)"" IL_0032: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" IL_0037: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_003c: stloc.s V_5 - IL_003e: ldloca.s V_5 + IL_003c: stloc.s V_4 + IL_003e: ldloca.s V_4 IL_0040: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" IL_0045: brtrue.s IL_0088 IL_0047: ldarg.0 @@ -9656,17 +9587,17 @@ .locals init (int V_0, IL_004a: stloc.0 IL_004b: stfld ""int Program.d__2.<>1__state"" IL_0050: ldarg.0 - IL_0051: ldloc.s V_5 + IL_0051: ldloc.s V_4 IL_0053: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" IL_0058: ldarg.0 IL_0059: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_005e: ldloca.s V_5 + IL_005e: ldloca.s V_4 IL_0060: ldarg.0 IL_0061: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" IL_0066: leave IL_013d IL_006b: ldarg.0 IL_006c: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_0071: stloc.s V_5 + IL_0071: stloc.s V_4 IL_0073: ldarg.0 IL_0074: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" IL_0079: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" @@ -9675,13 +9606,12 @@ .locals init (int V_0, IL_0081: dup IL_0082: stloc.0 IL_0083: stfld ""int Program.d__2.<>1__state"" - IL_0088: ldloca.s V_5 + IL_0088: ldloca.s V_4 IL_008a: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" IL_008f: stloc.1 - IL_0090: ldloca.s V_4 - IL_0092: initobj ""T"" - IL_0098: ldloc.s V_4 - IL_009a: box ""T"" + IL_0090: ldtoken ""T"" + IL_0095: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_009a: call ""bool System.Type.IsValueType.get"" IL_009f: brtrue.s IL_00a9 IL_00a1: ldarg.0 IL_00a2: ldflda ""T Program.d__2.<>7__wrap1"" @@ -9700,10 +9630,9 @@ .locals init (int V_0, IL_00cb: brtrue.s IL_0103 IL_00cd: ldc.i4.1 IL_00ce: stloc.3 - IL_00cf: ldloca.s V_4 - IL_00d1: initobj ""T"" - IL_00d7: ldloc.s V_4 - IL_00d9: box ""T"" + IL_00cf: ldtoken ""T"" + IL_00d4: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_00d9: call ""bool System.Type.IsValueType.get"" IL_00de: brtrue.s IL_00e8 IL_00e0: ldarg.0 IL_00e1: ldflda ""T Program.d__2.<>7__wrap1"" @@ -9714,7 +9643,7 @@ .locals init (int V_0, IL_00ef: ldloc.3 IL_00f0: newobj ""int?..ctor(int)"" IL_00f5: dup - IL_00f6: stloc.s V_6 + IL_00f6: stloc.s V_5 IL_00f8: constrained. ""T"" IL_00fe: callvirt ""void IMoveable.this[int].set"" IL_0103: ldarg.0 @@ -9724,13 +9653,13 @@ .locals init (int V_0, } catch System.Exception { - IL_0111: stloc.s V_7 + IL_0111: stloc.s V_6 IL_0113: ldarg.0 IL_0114: ldc.i4.s -2 IL_0116: stfld ""int Program.d__2.<>1__state"" IL_011b: ldarg.0 IL_011c: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_0121: ldloc.s V_7 + IL_0121: ldloc.s V_6 IL_0123: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" IL_0128: leave.s IL_013d } @@ -10160,10 +10089,9 @@ .locals init (int V_0, int V_3, int? V_4, int V_5, - T V_6, - System.Runtime.CompilerServices.TaskAwaiter V_7, - int? V_8, - System.Exception V_9) + System.Runtime.CompilerServices.TaskAwaiter V_6, + int? V_7, + System.Exception V_8) IL_0000: ldarg.0 IL_0001: ldfld ""int Program.d__2.<>1__state"" IL_0006: stloc.0 @@ -10209,10 +10137,9 @@ .locals init (int V_0, IL_0062: stfld ""int Program.d__2.<>1__state"" IL_0067: ldloca.s V_1 IL_0069: call ""void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()"" - IL_006e: ldloca.s V_6 - IL_0070: initobj ""T"" - IL_0076: ldloc.s V_6 - IL_0078: box ""T"" + IL_006e: ldtoken ""T"" + IL_0073: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0078: call ""bool System.Type.IsValueType.get"" IL_007d: brtrue.s IL_008b IL_007f: ldarg.0 IL_0080: ldarg.0 @@ -10223,8 +10150,8 @@ .locals init (int V_0, IL_0091: call ""int Program.GetOffset(ref T)"" IL_0096: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" IL_009b: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_00a0: stloc.s V_7 - IL_00a2: ldloca.s V_7 + IL_00a0: stloc.s V_6 + IL_00a2: ldloca.s V_6 IL_00a4: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" IL_00a9: brtrue.s IL_00ec IL_00ab: ldarg.0 @@ -10233,17 +10160,17 @@ .locals init (int V_0, IL_00ae: stloc.0 IL_00af: stfld ""int Program.d__2.<>1__state"" IL_00b4: ldarg.0 - IL_00b5: ldloc.s V_7 + IL_00b5: ldloc.s V_6 IL_00b7: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__2"" IL_00bc: ldarg.0 IL_00bd: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_00c2: ldloca.s V_7 + IL_00c2: ldloca.s V_6 IL_00c4: ldarg.0 IL_00c5: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" IL_00ca: leave IL_01a5 IL_00cf: ldarg.0 IL_00d0: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__2"" - IL_00d5: stloc.s V_7 + IL_00d5: stloc.s V_6 IL_00d7: ldarg.0 IL_00d8: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__2"" IL_00dd: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" @@ -10252,13 +10179,12 @@ .locals init (int V_0, IL_00e5: dup IL_00e6: stloc.0 IL_00e7: stfld ""int Program.d__2.<>1__state"" - IL_00ec: ldloca.s V_7 + IL_00ec: ldloca.s V_6 IL_00ee: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" IL_00f3: stloc.3 - IL_00f4: ldloca.s V_6 - IL_00f6: initobj ""T"" - IL_00fc: ldloc.s V_6 - IL_00fe: box ""T"" + IL_00f4: ldtoken ""T"" + IL_00f9: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_00fe: call ""bool System.Type.IsValueType.get"" IL_0103: brtrue.s IL_010d IL_0105: ldarg.0 IL_0106: ldflda ""T Program.d__2.<>7__wrap1"" @@ -10277,10 +10203,9 @@ .locals init (int V_0, IL_0131: brtrue.s IL_016b IL_0133: ldc.i4.1 IL_0134: stloc.s V_5 - IL_0136: ldloca.s V_6 - IL_0138: initobj ""T"" - IL_013e: ldloc.s V_6 - IL_0140: box ""T"" + IL_0136: ldtoken ""T"" + IL_013b: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0140: call ""bool System.Type.IsValueType.get"" IL_0145: brtrue.s IL_014f IL_0147: ldarg.0 IL_0148: ldflda ""T Program.d__2.<>7__wrap1"" @@ -10291,7 +10216,7 @@ .locals init (int V_0, IL_0156: ldloc.s V_5 IL_0158: newobj ""int?..ctor(int)"" IL_015d: dup - IL_015e: stloc.s V_8 + IL_015e: stloc.s V_7 IL_0160: constrained. ""T"" IL_0166: callvirt ""void IMoveable.this[int].set"" IL_016b: ldarg.0 @@ -10301,13 +10226,13 @@ .locals init (int V_0, } catch System.Exception { - IL_0179: stloc.s V_9 + IL_0179: stloc.s V_8 IL_017b: ldarg.0 IL_017c: ldc.i4.s -2 IL_017e: stfld ""int Program.d__2.<>1__state"" IL_0183: ldarg.0 IL_0184: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_0189: ldloc.s V_9 + IL_0189: ldloc.s V_8 IL_018b: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" IL_0190: leave.s IL_01a5 } @@ -10639,32 +10564,31 @@ .locals init (T& V_0, verifier.VerifyIL("Program.Shift2", @" { - // Code size 62 (0x3e) + // Code size 63 (0x3f) .maxstack 4 .locals init (T& V_0, T V_1) IL_0000: ldarga.s V_0 IL_0002: stloc.0 IL_0003: ldloc.0 - IL_0004: ldloca.s V_1 - IL_0006: initobj ""T"" - IL_000c: ldloc.1 - IL_000d: box ""T"" - IL_0012: brtrue.s IL_001c - IL_0014: ldobj ""T"" - IL_0019: stloc.1 - IL_001a: ldloca.s V_1 - IL_001c: ldc.i4.1 - IL_001d: ldloc.0 - IL_001e: ldc.i4.1 - IL_001f: constrained. ""T"" - IL_0025: callvirt ""int IMoveable.this[int].get"" - IL_002a: ldarga.s V_0 - IL_002c: call ""int Program.GetOffset(ref T)"" - IL_0031: add - IL_0032: constrained. ""T"" - IL_0038: callvirt ""void IMoveable.this[int].set"" - IL_003d: ret + IL_0004: ldtoken ""T"" + IL_0009: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000e: call ""bool System.Type.IsValueType.get"" + IL_0013: brtrue.s IL_001d + IL_0015: ldobj ""T"" + IL_001a: stloc.1 + IL_001b: ldloca.s V_1 + IL_001d: ldc.i4.1 + IL_001e: ldloc.0 + IL_001f: ldc.i4.1 + IL_0020: constrained. ""T"" + IL_0026: callvirt ""int IMoveable.this[int].get"" + IL_002b: ldarga.s V_0 + IL_002d: call ""int Program.GetOffset(ref T)"" + IL_0032: add + IL_0033: constrained. ""T"" + IL_0039: callvirt ""void IMoveable.this[int].set"" + IL_003e: ret } "); } @@ -10857,45 +10781,44 @@ .locals init (T& V_0, verifier.VerifyIL("Program.Shift2", @" { - // Code size 60 (0x3c) + // Code size 61 (0x3d) .maxstack 4 .locals init (T& V_0, T V_1) IL_0000: ldarg.0 IL_0001: stloc.0 IL_0002: ldloc.0 - IL_0003: ldloca.s V_1 - IL_0005: initobj ""T"" - IL_000b: ldloc.1 - IL_000c: box ""T"" - IL_0011: brtrue.s IL_001b - IL_0013: ldobj ""T"" - IL_0018: stloc.1 - IL_0019: ldloca.s V_1 - IL_001b: ldc.i4.1 - IL_001c: ldloc.0 - IL_001d: ldc.i4.1 - IL_001e: constrained. ""T"" - IL_0024: callvirt ""int IMoveable.this[int].get"" - IL_0029: ldarg.0 - IL_002a: call ""int Program.GetOffset(ref T)"" - IL_002f: add - IL_0030: constrained. ""T"" - IL_0036: callvirt ""void IMoveable.this[int].set"" - IL_003b: ret -} -"); - } - - [Fact] - [WorkItem(63221, "https://github.com/dotnet/roslyn/issues/63221")] - public void GenericTypeParameterAsReceiver_Assignment_Compound_Indexer_Struct_Value_Ref() - { - var source = @" -using System; - -interface IMoveable -{ + IL_0003: ldtoken ""T"" + IL_0008: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000d: call ""bool System.Type.IsValueType.get"" + IL_0012: brtrue.s IL_001c + IL_0014: ldobj ""T"" + IL_0019: stloc.1 + IL_001a: ldloca.s V_1 + IL_001c: ldc.i4.1 + IL_001d: ldloc.0 + IL_001e: ldc.i4.1 + IL_001f: constrained. ""T"" + IL_0025: callvirt ""int IMoveable.this[int].get"" + IL_002a: ldarg.0 + IL_002b: call ""int Program.GetOffset(ref T)"" + IL_0030: add + IL_0031: constrained. ""T"" + IL_0037: callvirt ""void IMoveable.this[int].set"" + IL_003c: ret +} +"); + } + + [Fact] + [WorkItem(63221, "https://github.com/dotnet/roslyn/issues/63221")] + public void GenericTypeParameterAsReceiver_Assignment_Compound_Indexer_Struct_Value_Ref() + { + var source = @" +using System; + +interface IMoveable +{ int this[int i] {get;set;} } @@ -11162,100 +11085,97 @@ .locals init (int V_0, .maxstack 4 .locals init (int V_0, int V_1, - T V_2, - System.Runtime.CompilerServices.TaskAwaiter V_3, - System.Exception V_4) + System.Runtime.CompilerServices.TaskAwaiter V_2, + System.Exception V_3) IL_0000: ldarg.0 IL_0001: ldfld ""int Program.d__2.<>1__state"" IL_0006: stloc.0 .try { IL_0007: ldloc.0 - IL_0008: brfalse.s IL_0080 - IL_000a: ldloca.s V_2 - IL_000c: initobj ""T"" - IL_0012: ldloc.2 - IL_0013: box ""T"" - IL_0018: brtrue.s IL_0026 - IL_001a: ldarg.0 + IL_0008: brfalse.s IL_0081 + IL_000a: ldtoken ""T"" + IL_000f: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0014: call ""bool System.Type.IsValueType.get"" + IL_0019: brtrue.s IL_0027 IL_001b: ldarg.0 - IL_001c: ldfld ""T Program.d__2.item"" - IL_0021: stfld ""T Program.d__2.<>7__wrap1"" - IL_0026: ldarg.0 + IL_001c: ldarg.0 + IL_001d: ldfld ""T Program.d__2.item"" + IL_0022: stfld ""T Program.d__2.<>7__wrap1"" IL_0027: ldarg.0 - IL_0028: ldflda ""T Program.d__2.item"" - IL_002d: ldc.i4.1 - IL_002e: constrained. ""T"" - IL_0034: callvirt ""int IMoveable.this[int].get"" - IL_0039: stfld ""int Program.d__2.<>7__wrap2"" - IL_003e: ldarg.0 - IL_003f: ldflda ""T Program.d__2.item"" - IL_0044: call ""int Program.GetOffset(ref T)"" - IL_0049: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" - IL_004e: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_0053: stloc.3 - IL_0054: ldloca.s V_3 - IL_0056: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_005b: brtrue.s IL_009c - IL_005d: ldarg.0 - IL_005e: ldc.i4.0 - IL_005f: dup - IL_0060: stloc.0 - IL_0061: stfld ""int Program.d__2.<>1__state"" - IL_0066: ldarg.0 - IL_0067: ldloc.3 - IL_0068: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_006d: ldarg.0 - IL_006e: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_0073: ldloca.s V_3 - IL_0075: ldarg.0 - IL_0076: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" - IL_007b: leave IL_0110 - IL_0080: ldarg.0 - IL_0081: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_0086: stloc.3 - IL_0087: ldarg.0 - IL_0088: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_008d: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_0093: ldarg.0 - IL_0094: ldc.i4.m1 - IL_0095: dup - IL_0096: stloc.0 - IL_0097: stfld ""int Program.d__2.<>1__state"" - IL_009c: ldloca.s V_3 - IL_009e: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_00a3: stloc.1 - IL_00a4: ldloca.s V_2 - IL_00a6: initobj ""T"" - IL_00ac: ldloc.2 - IL_00ad: box ""T"" - IL_00b2: brtrue.s IL_00bc - IL_00b4: ldarg.0 - IL_00b5: ldflda ""T Program.d__2.<>7__wrap1"" - IL_00ba: br.s IL_00c2 - IL_00bc: ldarg.0 - IL_00bd: ldflda ""T Program.d__2.item"" - IL_00c2: ldc.i4.1 - IL_00c3: ldarg.0 - IL_00c4: ldfld ""int Program.d__2.<>7__wrap2"" - IL_00c9: ldloc.1 - IL_00ca: add - IL_00cb: constrained. ""T"" - IL_00d1: callvirt ""void IMoveable.this[int].set"" - IL_00d6: ldarg.0 - IL_00d7: ldflda ""T Program.d__2.<>7__wrap1"" - IL_00dc: initobj ""T"" - IL_00e2: leave.s IL_00fd + IL_0028: ldarg.0 + IL_0029: ldflda ""T Program.d__2.item"" + IL_002e: ldc.i4.1 + IL_002f: constrained. ""T"" + IL_0035: callvirt ""int IMoveable.this[int].get"" + IL_003a: stfld ""int Program.d__2.<>7__wrap2"" + IL_003f: ldarg.0 + IL_0040: ldflda ""T Program.d__2.item"" + IL_0045: call ""int Program.GetOffset(ref T)"" + IL_004a: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" + IL_004f: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_0054: stloc.2 + IL_0055: ldloca.s V_2 + IL_0057: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_005c: brtrue.s IL_009d + IL_005e: ldarg.0 + IL_005f: ldc.i4.0 + IL_0060: dup + IL_0061: stloc.0 + IL_0062: stfld ""int Program.d__2.<>1__state"" + IL_0067: ldarg.0 + IL_0068: ldloc.2 + IL_0069: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_006e: ldarg.0 + IL_006f: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_0074: ldloca.s V_2 + IL_0076: ldarg.0 + IL_0077: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" + IL_007c: leave IL_0110 + IL_0081: ldarg.0 + IL_0082: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_0087: stloc.2 + IL_0088: ldarg.0 + IL_0089: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_008e: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_0094: ldarg.0 + IL_0095: ldc.i4.m1 + IL_0096: dup + IL_0097: stloc.0 + IL_0098: stfld ""int Program.d__2.<>1__state"" + IL_009d: ldloca.s V_2 + IL_009f: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_00a4: stloc.1 + IL_00a5: ldtoken ""T"" + IL_00aa: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_00af: call ""bool System.Type.IsValueType.get"" + IL_00b4: brtrue.s IL_00be + IL_00b6: ldarg.0 + IL_00b7: ldflda ""T Program.d__2.<>7__wrap1"" + IL_00bc: br.s IL_00c4 + IL_00be: ldarg.0 + IL_00bf: ldflda ""T Program.d__2.item"" + IL_00c4: ldc.i4.1 + IL_00c5: ldarg.0 + IL_00c6: ldfld ""int Program.d__2.<>7__wrap2"" + IL_00cb: ldloc.1 + IL_00cc: add + IL_00cd: constrained. ""T"" + IL_00d3: callvirt ""void IMoveable.this[int].set"" + IL_00d8: ldarg.0 + IL_00d9: ldflda ""T Program.d__2.<>7__wrap1"" + IL_00de: initobj ""T"" + IL_00e4: leave.s IL_00fd } catch System.Exception { - IL_00e4: stloc.s V_4 - IL_00e6: ldarg.0 - IL_00e7: ldc.i4.s -2 - IL_00e9: stfld ""int Program.d__2.<>1__state"" - IL_00ee: ldarg.0 - IL_00ef: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_00f4: ldloc.s V_4 + IL_00e6: stloc.3 + IL_00e7: ldarg.0 + IL_00e8: ldc.i4.s -2 + IL_00ea: stfld ""int Program.d__2.<>1__state"" + IL_00ef: ldarg.0 + IL_00f0: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_00f5: ldloc.3 IL_00f6: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" IL_00fb: leave.s IL_0110 } @@ -11543,14 +11463,12 @@ .maxstack 4 .locals init (T& V_0, T V_1, T& V_2, - int V_3, - T V_4) + int V_3) IL_0000: ldarga.s V_0 IL_0002: stloc.2 - IL_0003: ldloca.s V_4 - IL_0005: initobj ""T"" - IL_000b: ldloc.s V_4 - IL_000d: box ""T"" + IL_0003: ldtoken ""T"" + IL_0008: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000d: call ""bool System.Type.IsValueType.get"" IL_0012: brtrue.s IL_001f IL_0014: ldloc.2 IL_0015: ldobj ""T"" @@ -11779,14 +11697,12 @@ .maxstack 4 .locals init (T& V_0, T V_1, T& V_2, - int V_3, - T V_4) + int V_3) IL_0000: ldarg.0 IL_0001: stloc.2 - IL_0002: ldloca.s V_4 - IL_0004: initobj ""T"" - IL_000a: ldloc.s V_4 - IL_000c: box ""T"" + IL_0002: ldtoken ""T"" + IL_0007: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000c: call ""bool System.Type.IsValueType.get"" IL_0011: brtrue.s IL_001e IL_0013: ldloc.2 IL_0014: ldobj ""T"" @@ -12106,9 +12022,8 @@ .maxstack 4 .locals init (int V_0, int V_1, int V_2, - T V_3, - System.Runtime.CompilerServices.TaskAwaiter V_4, - System.Exception V_5) + System.Runtime.CompilerServices.TaskAwaiter V_3, + System.Exception V_4) IL_0000: ldarg.0 IL_0001: ldfld ""int Program.d__2.<>1__state"" IL_0006: stloc.0 @@ -12116,78 +12031,75 @@ .locals init (int V_0, { IL_0007: ldloc.0 IL_0008: brfalse IL_00b0 - IL_000d: ldloca.s V_3 - IL_000f: initobj ""T"" - IL_0015: ldloc.3 - IL_0016: box ""T"" - IL_001b: brtrue.s IL_0029 - IL_001d: ldarg.0 + IL_000d: ldtoken ""T"" + IL_0012: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0017: call ""bool System.Type.IsValueType.get"" + IL_001c: brtrue.s IL_002a IL_001e: ldarg.0 - IL_001f: ldfld ""T Program.d__2.item"" - IL_0024: stfld ""T Program.d__2.<>7__wrap1"" - IL_0029: ldarg.0 - IL_002a: ldflda ""T Program.d__2.item"" - IL_002f: call ""int Program.GetOffset(ref T)"" - IL_0034: stloc.1 - IL_0035: ldarg.0 - IL_0036: ldloc.1 - IL_0037: stfld ""int Program.d__2.<>7__wrap2"" - IL_003c: ldarg.0 - IL_003d: ldloca.s V_3 - IL_003f: initobj ""T"" - IL_0045: ldloc.3 - IL_0046: box ""T"" - IL_004b: brtrue.s IL_0055 - IL_004d: ldarg.0 - IL_004e: ldflda ""T Program.d__2.<>7__wrap1"" - IL_0053: br.s IL_005b - IL_0055: ldarg.0 - IL_0056: ldflda ""T Program.d__2.item"" - IL_005b: ldloc.1 - IL_005c: constrained. ""T"" - IL_0062: callvirt ""int IMoveable.this[int].get"" - IL_0067: stfld ""int Program.d__2.<>7__wrap3"" - IL_006c: ldarg.0 - IL_006d: ldflda ""T Program.d__2.item"" - IL_0072: call ""int Program.GetOffset(ref T)"" - IL_0077: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" - IL_007c: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_0081: stloc.s V_4 - IL_0083: ldloca.s V_4 - IL_0085: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_008a: brtrue.s IL_00cd - IL_008c: ldarg.0 - IL_008d: ldc.i4.0 - IL_008e: dup - IL_008f: stloc.0 - IL_0090: stfld ""int Program.d__2.<>1__state"" - IL_0095: ldarg.0 - IL_0096: ldloc.s V_4 + IL_001f: ldarg.0 + IL_0020: ldfld ""T Program.d__2.item"" + IL_0025: stfld ""T Program.d__2.<>7__wrap1"" + IL_002a: ldarg.0 + IL_002b: ldflda ""T Program.d__2.item"" + IL_0030: call ""int Program.GetOffset(ref T)"" + IL_0035: stloc.1 + IL_0036: ldarg.0 + IL_0037: ldloc.1 + IL_0038: stfld ""int Program.d__2.<>7__wrap2"" + IL_003d: ldarg.0 + IL_003e: ldtoken ""T"" + IL_0043: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0048: call ""bool System.Type.IsValueType.get"" + IL_004d: brtrue.s IL_0057 + IL_004f: ldarg.0 + IL_0050: ldflda ""T Program.d__2.<>7__wrap1"" + IL_0055: br.s IL_005d + IL_0057: ldarg.0 + IL_0058: ldflda ""T Program.d__2.item"" + IL_005d: ldloc.1 + IL_005e: constrained. ""T"" + IL_0064: callvirt ""int IMoveable.this[int].get"" + IL_0069: stfld ""int Program.d__2.<>7__wrap3"" + IL_006e: ldarg.0 + IL_006f: ldflda ""T Program.d__2.item"" + IL_0074: call ""int Program.GetOffset(ref T)"" + IL_0079: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" + IL_007e: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_0083: stloc.3 + IL_0084: ldloca.s V_3 + IL_0086: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_008b: brtrue.s IL_00cc + IL_008d: ldarg.0 + IL_008e: ldc.i4.0 + IL_008f: dup + IL_0090: stloc.0 + IL_0091: stfld ""int Program.d__2.<>1__state"" + IL_0096: ldarg.0 + IL_0097: ldloc.3 IL_0098: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" IL_009d: ldarg.0 IL_009e: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_00a3: ldloca.s V_4 + IL_00a3: ldloca.s V_3 IL_00a5: ldarg.0 IL_00a6: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" IL_00ab: leave IL_0146 IL_00b0: ldarg.0 IL_00b1: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_00b6: stloc.s V_4 - IL_00b8: ldarg.0 - IL_00b9: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_00be: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_00c4: ldarg.0 - IL_00c5: ldc.i4.m1 - IL_00c6: dup - IL_00c7: stloc.0 - IL_00c8: stfld ""int Program.d__2.<>1__state"" - IL_00cd: ldloca.s V_4 - IL_00cf: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_00d4: stloc.2 - IL_00d5: ldloca.s V_3 - IL_00d7: initobj ""T"" - IL_00dd: ldloc.3 - IL_00de: box ""T"" + IL_00b6: stloc.3 + IL_00b7: ldarg.0 + IL_00b8: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_00bd: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_00c3: ldarg.0 + IL_00c4: ldc.i4.m1 + IL_00c5: dup + IL_00c6: stloc.0 + IL_00c7: stfld ""int Program.d__2.<>1__state"" + IL_00cc: ldloca.s V_3 + IL_00ce: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_00d3: stloc.2 + IL_00d4: ldtoken ""T"" + IL_00d9: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_00de: call ""bool System.Type.IsValueType.get"" IL_00e3: brtrue.s IL_00ed IL_00e5: ldarg.0 IL_00e6: ldflda ""T Program.d__2.<>7__wrap1"" @@ -12209,13 +12121,13 @@ .locals init (int V_0, } catch System.Exception { - IL_011a: stloc.s V_5 + IL_011a: stloc.s V_4 IL_011c: ldarg.0 IL_011d: ldc.i4.s -2 IL_011f: stfld ""int Program.d__2.<>1__state"" IL_0124: ldarg.0 IL_0125: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_012a: ldloc.s V_5 + IL_012a: ldloc.s V_4 IL_012c: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" IL_0131: leave.s IL_0146 } @@ -12582,120 +12494,116 @@ .locals init (int V_0, verifier.VerifyIL("Program.d__2.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @" { - // Code size 295 (0x127) + // Code size 296 (0x128) .maxstack 4 .locals init (int V_0, int V_1, - T V_2, - System.Runtime.CompilerServices.TaskAwaiter V_3, - System.Exception V_4) + System.Runtime.CompilerServices.TaskAwaiter V_2, + System.Exception V_3) IL_0000: ldarg.0 IL_0001: ldfld ""int Program.d__2.<>1__state"" IL_0006: stloc.0 .try { IL_0007: ldloc.0 - IL_0008: brfalse.s IL_0068 - IL_000a: ldloca.s V_2 - IL_000c: initobj ""T"" - IL_0012: ldloc.2 - IL_0013: box ""T"" - IL_0018: brtrue.s IL_0026 - IL_001a: ldarg.0 + IL_0008: brfalse.s IL_0069 + IL_000a: ldtoken ""T"" + IL_000f: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0014: call ""bool System.Type.IsValueType.get"" + IL_0019: brtrue.s IL_0027 IL_001b: ldarg.0 - IL_001c: ldfld ""T Program.d__2.item"" - IL_0021: stfld ""T Program.d__2.<>7__wrap1"" - IL_0026: ldarg.0 - IL_0027: ldflda ""T Program.d__2.item"" - IL_002c: call ""int Program.GetOffset(ref T)"" - IL_0031: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" - IL_0036: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_003b: stloc.3 - IL_003c: ldloca.s V_3 - IL_003e: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_0043: brtrue.s IL_0084 - IL_0045: ldarg.0 - IL_0046: ldc.i4.0 - IL_0047: dup - IL_0048: stloc.0 - IL_0049: stfld ""int Program.d__2.<>1__state"" - IL_004e: ldarg.0 - IL_004f: ldloc.3 - IL_0050: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_0055: ldarg.0 - IL_0056: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_005b: ldloca.s V_3 - IL_005d: ldarg.0 - IL_005e: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" - IL_0063: leave IL_0126 - IL_0068: ldarg.0 - IL_0069: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_006e: stloc.3 - IL_006f: ldarg.0 - IL_0070: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_0075: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_007b: ldarg.0 - IL_007c: ldc.i4.m1 - IL_007d: dup - IL_007e: stloc.0 - IL_007f: stfld ""int Program.d__2.<>1__state"" - IL_0084: ldloca.s V_3 - IL_0086: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_008b: stloc.1 - IL_008c: ldloca.s V_2 - IL_008e: initobj ""T"" - IL_0094: ldloc.2 - IL_0095: box ""T"" - IL_009a: brtrue.s IL_00a4 - IL_009c: ldarg.0 - IL_009d: ldflda ""T Program.d__2.<>7__wrap1"" - IL_00a2: br.s IL_00aa - IL_00a4: ldarg.0 - IL_00a5: ldflda ""T Program.d__2.item"" - IL_00aa: ldloc.1 - IL_00ab: ldloca.s V_2 - IL_00ad: initobj ""T"" - IL_00b3: ldloc.2 - IL_00b4: box ""T"" - IL_00b9: brtrue.s IL_00c3 - IL_00bb: ldarg.0 - IL_00bc: ldflda ""T Program.d__2.<>7__wrap1"" - IL_00c1: br.s IL_00c9 - IL_00c3: ldarg.0 - IL_00c4: ldflda ""T Program.d__2.item"" - IL_00c9: ldloc.1 - IL_00ca: constrained. ""T"" - IL_00d0: callvirt ""int IMoveable.this[int].get"" - IL_00d5: ldarg.0 - IL_00d6: ldflda ""T Program.d__2.item"" - IL_00db: call ""int Program.GetOffset(ref T)"" - IL_00e0: add - IL_00e1: constrained. ""T"" - IL_00e7: callvirt ""void IMoveable.this[int].set"" - IL_00ec: ldarg.0 - IL_00ed: ldflda ""T Program.d__2.<>7__wrap1"" - IL_00f2: initobj ""T"" - IL_00f8: leave.s IL_0113 + IL_001c: ldarg.0 + IL_001d: ldfld ""T Program.d__2.item"" + IL_0022: stfld ""T Program.d__2.<>7__wrap1"" + IL_0027: ldarg.0 + IL_0028: ldflda ""T Program.d__2.item"" + IL_002d: call ""int Program.GetOffset(ref T)"" + IL_0032: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" + IL_0037: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_003c: stloc.2 + IL_003d: ldloca.s V_2 + IL_003f: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_0044: brtrue.s IL_0085 + IL_0046: ldarg.0 + IL_0047: ldc.i4.0 + IL_0048: dup + IL_0049: stloc.0 + IL_004a: stfld ""int Program.d__2.<>1__state"" + IL_004f: ldarg.0 + IL_0050: ldloc.2 + IL_0051: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_0056: ldarg.0 + IL_0057: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_005c: ldloca.s V_2 + IL_005e: ldarg.0 + IL_005f: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" + IL_0064: leave IL_0127 + IL_0069: ldarg.0 + IL_006a: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_006f: stloc.2 + IL_0070: ldarg.0 + IL_0071: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_0076: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_007c: ldarg.0 + IL_007d: ldc.i4.m1 + IL_007e: dup + IL_007f: stloc.0 + IL_0080: stfld ""int Program.d__2.<>1__state"" + IL_0085: ldloca.s V_2 + IL_0087: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_008c: stloc.1 + IL_008d: ldtoken ""T"" + IL_0092: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0097: call ""bool System.Type.IsValueType.get"" + IL_009c: brtrue.s IL_00a6 + IL_009e: ldarg.0 + IL_009f: ldflda ""T Program.d__2.<>7__wrap1"" + IL_00a4: br.s IL_00ac + IL_00a6: ldarg.0 + IL_00a7: ldflda ""T Program.d__2.item"" + IL_00ac: ldloc.1 + IL_00ad: ldtoken ""T"" + IL_00b2: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_00b7: call ""bool System.Type.IsValueType.get"" + IL_00bc: brtrue.s IL_00c6 + IL_00be: ldarg.0 + IL_00bf: ldflda ""T Program.d__2.<>7__wrap1"" + IL_00c4: br.s IL_00cc + IL_00c6: ldarg.0 + IL_00c7: ldflda ""T Program.d__2.item"" + IL_00cc: ldloc.1 + IL_00cd: constrained. ""T"" + IL_00d3: callvirt ""int IMoveable.this[int].get"" + IL_00d8: ldarg.0 + IL_00d9: ldflda ""T Program.d__2.item"" + IL_00de: call ""int Program.GetOffset(ref T)"" + IL_00e3: add + IL_00e4: constrained. ""T"" + IL_00ea: callvirt ""void IMoveable.this[int].set"" + IL_00ef: ldarg.0 + IL_00f0: ldflda ""T Program.d__2.<>7__wrap1"" + IL_00f5: initobj ""T"" + IL_00fb: leave.s IL_0114 } catch System.Exception { - IL_00fa: stloc.s V_4 - IL_00fc: ldarg.0 - IL_00fd: ldc.i4.s -2 - IL_00ff: stfld ""int Program.d__2.<>1__state"" - IL_0104: ldarg.0 - IL_0105: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_010a: ldloc.s V_4 - IL_010c: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" - IL_0111: leave.s IL_0126 + IL_00fd: stloc.3 + IL_00fe: ldarg.0 + IL_00ff: ldc.i4.s -2 + IL_0101: stfld ""int Program.d__2.<>1__state"" + IL_0106: ldarg.0 + IL_0107: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_010c: ldloc.3 + IL_010d: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" + IL_0112: leave.s IL_0127 } - IL_0113: ldarg.0 - IL_0114: ldc.i4.s -2 - IL_0116: stfld ""int Program.d__2.<>1__state"" - IL_011b: ldarg.0 - IL_011c: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_0121: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" - IL_0126: ret + IL_0114: ldarg.0 + IL_0115: ldc.i4.s -2 + IL_0117: stfld ""int Program.d__2.<>1__state"" + IL_011c: ldarg.0 + IL_011d: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_0122: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" + IL_0127: ret } "); } @@ -13095,167 +13003,163 @@ .locals init (int V_0, verifier.VerifyIL("Program.d__2.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @" { - // Code size 424 (0x1a8) + // Code size 421 (0x1a5) .maxstack 4 .locals init (int V_0, int V_1, int V_2, - T V_3, - System.Runtime.CompilerServices.TaskAwaiter V_4, - System.Exception V_5) + System.Runtime.CompilerServices.TaskAwaiter V_3, + System.Exception V_4) IL_0000: ldarg.0 IL_0001: ldfld ""int Program.d__2.<>1__state"" IL_0006: stloc.0 .try { IL_0007: ldloc.0 - IL_0008: brfalse.s IL_0071 + IL_0008: brfalse.s IL_0070 IL_000a: ldloc.0 IL_000b: ldc.i4.1 - IL_000c: beq IL_0111 - IL_0011: ldloca.s V_3 - IL_0013: initobj ""T"" - IL_0019: ldloc.3 - IL_001a: box ""T"" - IL_001f: brtrue.s IL_002d - IL_0021: ldarg.0 + IL_000c: beq IL_010e + IL_0011: ldtoken ""T"" + IL_0016: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_001b: call ""bool System.Type.IsValueType.get"" + IL_0020: brtrue.s IL_002e IL_0022: ldarg.0 - IL_0023: ldfld ""T Program.d__2.item"" - IL_0028: stfld ""T Program.d__2.<>7__wrap1"" - IL_002d: ldarg.0 - IL_002e: ldflda ""T Program.d__2.item"" - IL_0033: call ""int Program.GetOffset(ref T)"" - IL_0038: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" - IL_003d: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_0042: stloc.s V_4 - IL_0044: ldloca.s V_4 + IL_0023: ldarg.0 + IL_0024: ldfld ""T Program.d__2.item"" + IL_0029: stfld ""T Program.d__2.<>7__wrap1"" + IL_002e: ldarg.0 + IL_002f: ldflda ""T Program.d__2.item"" + IL_0034: call ""int Program.GetOffset(ref T)"" + IL_0039: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" + IL_003e: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_0043: stloc.3 + IL_0044: ldloca.s V_3 IL_0046: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_004b: brtrue.s IL_008e + IL_004b: brtrue.s IL_008c IL_004d: ldarg.0 IL_004e: ldc.i4.0 IL_004f: dup IL_0050: stloc.0 IL_0051: stfld ""int Program.d__2.<>1__state"" IL_0056: ldarg.0 - IL_0057: ldloc.s V_4 - IL_0059: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_005e: ldarg.0 - IL_005f: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_0064: ldloca.s V_4 - IL_0066: ldarg.0 - IL_0067: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" - IL_006c: leave IL_01a7 - IL_0071: ldarg.0 - IL_0072: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_0077: stloc.s V_4 - IL_0079: ldarg.0 - IL_007a: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_007f: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_0085: ldarg.0 - IL_0086: ldc.i4.m1 - IL_0087: dup - IL_0088: stloc.0 - IL_0089: stfld ""int Program.d__2.<>1__state"" - IL_008e: ldloca.s V_4 - IL_0090: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_0095: stloc.1 - IL_0096: ldarg.0 - IL_0097: ldloc.1 - IL_0098: stfld ""int Program.d__2.<>7__wrap2"" - IL_009d: ldarg.0 - IL_009e: ldloca.s V_3 - IL_00a0: initobj ""T"" - IL_00a6: ldloc.3 - IL_00a7: box ""T"" - IL_00ac: brtrue.s IL_00b6 - IL_00ae: ldarg.0 - IL_00af: ldflda ""T Program.d__2.<>7__wrap1"" - IL_00b4: br.s IL_00bc - IL_00b6: ldarg.0 - IL_00b7: ldflda ""T Program.d__2.item"" - IL_00bc: ldloc.1 - IL_00bd: constrained. ""T"" - IL_00c3: callvirt ""int IMoveable.this[int].get"" - IL_00c8: stfld ""int Program.d__2.<>7__wrap3"" - IL_00cd: ldarg.0 - IL_00ce: ldflda ""T Program.d__2.item"" - IL_00d3: call ""int Program.GetOffset(ref T)"" - IL_00d8: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" - IL_00dd: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_00e2: stloc.s V_4 - IL_00e4: ldloca.s V_4 - IL_00e6: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_00eb: brtrue.s IL_012e - IL_00ed: ldarg.0 - IL_00ee: ldc.i4.1 - IL_00ef: dup - IL_00f0: stloc.0 - IL_00f1: stfld ""int Program.d__2.<>1__state"" - IL_00f6: ldarg.0 - IL_00f7: ldloc.s V_4 - IL_00f9: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_00fe: ldarg.0 - IL_00ff: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_0104: ldloca.s V_4 - IL_0106: ldarg.0 - IL_0107: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" - IL_010c: leave IL_01a7 - IL_0111: ldarg.0 - IL_0112: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_0117: stloc.s V_4 - IL_0119: ldarg.0 - IL_011a: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_011f: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_0125: ldarg.0 - IL_0126: ldc.i4.m1 - IL_0127: dup - IL_0128: stloc.0 - IL_0129: stfld ""int Program.d__2.<>1__state"" - IL_012e: ldloca.s V_4 - IL_0130: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_0135: stloc.2 - IL_0136: ldloca.s V_3 - IL_0138: initobj ""T"" - IL_013e: ldloc.3 - IL_013f: box ""T"" - IL_0144: brtrue.s IL_014e - IL_0146: ldarg.0 - IL_0147: ldflda ""T Program.d__2.<>7__wrap1"" - IL_014c: br.s IL_0154 - IL_014e: ldarg.0 - IL_014f: ldflda ""T Program.d__2.item"" - IL_0154: ldarg.0 - IL_0155: ldfld ""int Program.d__2.<>7__wrap2"" - IL_015a: ldarg.0 - IL_015b: ldfld ""int Program.d__2.<>7__wrap3"" - IL_0160: ldloc.2 - IL_0161: add - IL_0162: constrained. ""T"" - IL_0168: callvirt ""void IMoveable.this[int].set"" - IL_016d: ldarg.0 - IL_016e: ldflda ""T Program.d__2.<>7__wrap1"" - IL_0173: initobj ""T"" - IL_0179: leave.s IL_0194 + IL_0057: ldloc.3 + IL_0058: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_005d: ldarg.0 + IL_005e: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_0063: ldloca.s V_3 + IL_0065: ldarg.0 + IL_0066: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" + IL_006b: leave IL_01a4 + IL_0070: ldarg.0 + IL_0071: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_0076: stloc.3 + IL_0077: ldarg.0 + IL_0078: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_007d: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_0083: ldarg.0 + IL_0084: ldc.i4.m1 + IL_0085: dup + IL_0086: stloc.0 + IL_0087: stfld ""int Program.d__2.<>1__state"" + IL_008c: ldloca.s V_3 + IL_008e: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_0093: stloc.1 + IL_0094: ldarg.0 + IL_0095: ldloc.1 + IL_0096: stfld ""int Program.d__2.<>7__wrap2"" + IL_009b: ldarg.0 + IL_009c: ldtoken ""T"" + IL_00a1: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_00a6: call ""bool System.Type.IsValueType.get"" + IL_00ab: brtrue.s IL_00b5 + IL_00ad: ldarg.0 + IL_00ae: ldflda ""T Program.d__2.<>7__wrap1"" + IL_00b3: br.s IL_00bb + IL_00b5: ldarg.0 + IL_00b6: ldflda ""T Program.d__2.item"" + IL_00bb: ldloc.1 + IL_00bc: constrained. ""T"" + IL_00c2: callvirt ""int IMoveable.this[int].get"" + IL_00c7: stfld ""int Program.d__2.<>7__wrap3"" + IL_00cc: ldarg.0 + IL_00cd: ldflda ""T Program.d__2.item"" + IL_00d2: call ""int Program.GetOffset(ref T)"" + IL_00d7: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" + IL_00dc: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_00e1: stloc.3 + IL_00e2: ldloca.s V_3 + IL_00e4: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_00e9: brtrue.s IL_012a + IL_00eb: ldarg.0 + IL_00ec: ldc.i4.1 + IL_00ed: dup + IL_00ee: stloc.0 + IL_00ef: stfld ""int Program.d__2.<>1__state"" + IL_00f4: ldarg.0 + IL_00f5: ldloc.3 + IL_00f6: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_00fb: ldarg.0 + IL_00fc: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_0101: ldloca.s V_3 + IL_0103: ldarg.0 + IL_0104: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" + IL_0109: leave IL_01a4 + IL_010e: ldarg.0 + IL_010f: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_0114: stloc.3 + IL_0115: ldarg.0 + IL_0116: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_011b: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_0121: ldarg.0 + IL_0122: ldc.i4.m1 + IL_0123: dup + IL_0124: stloc.0 + IL_0125: stfld ""int Program.d__2.<>1__state"" + IL_012a: ldloca.s V_3 + IL_012c: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_0131: stloc.2 + IL_0132: ldtoken ""T"" + IL_0137: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_013c: call ""bool System.Type.IsValueType.get"" + IL_0141: brtrue.s IL_014b + IL_0143: ldarg.0 + IL_0144: ldflda ""T Program.d__2.<>7__wrap1"" + IL_0149: br.s IL_0151 + IL_014b: ldarg.0 + IL_014c: ldflda ""T Program.d__2.item"" + IL_0151: ldarg.0 + IL_0152: ldfld ""int Program.d__2.<>7__wrap2"" + IL_0157: ldarg.0 + IL_0158: ldfld ""int Program.d__2.<>7__wrap3"" + IL_015d: ldloc.2 + IL_015e: add + IL_015f: constrained. ""T"" + IL_0165: callvirt ""void IMoveable.this[int].set"" + IL_016a: ldarg.0 + IL_016b: ldflda ""T Program.d__2.<>7__wrap1"" + IL_0170: initobj ""T"" + IL_0176: leave.s IL_0191 } catch System.Exception { - IL_017b: stloc.s V_5 - IL_017d: ldarg.0 - IL_017e: ldc.i4.s -2 - IL_0180: stfld ""int Program.d__2.<>1__state"" - IL_0185: ldarg.0 - IL_0186: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_018b: ldloc.s V_5 - IL_018d: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" - IL_0192: leave.s IL_01a7 + IL_0178: stloc.s V_4 + IL_017a: ldarg.0 + IL_017b: ldc.i4.s -2 + IL_017d: stfld ""int Program.d__2.<>1__state"" + IL_0182: ldarg.0 + IL_0183: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_0188: ldloc.s V_4 + IL_018a: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" + IL_018f: leave.s IL_01a4 } - IL_0194: ldarg.0 - IL_0195: ldc.i4.s -2 - IL_0197: stfld ""int Program.d__2.<>1__state"" - IL_019c: ldarg.0 - IL_019d: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_01a2: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" - IL_01a7: ret + IL_0191: ldarg.0 + IL_0192: ldc.i4.s -2 + IL_0194: stfld ""int Program.d__2.<>1__state"" + IL_0199: ldarg.0 + IL_019a: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_019f: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" + IL_01a4: ret } "); } @@ -13590,14 +13494,12 @@ .locals init (T& V_0, T& V_2, int? V_3, int V_4, - T V_5, - int? V_6) + int? V_5) IL_0000: ldarga.s V_0 IL_0002: stloc.2 - IL_0003: ldloca.s V_5 - IL_0005: initobj ""T"" - IL_000b: ldloc.s V_5 - IL_000d: box ""T"" + IL_0003: ldtoken ""T"" + IL_0008: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000d: call ""bool System.Type.IsValueType.get"" IL_0012: brtrue.s IL_001f IL_0014: ldloc.2 IL_0015: ldobj ""T"" @@ -13622,10 +13524,10 @@ .locals init (T& V_0, IL_0048: stloc.s V_4 IL_004a: ldloc.0 IL_004b: ldc.i4.1 - IL_004c: ldloca.s V_6 + IL_004c: ldloca.s V_5 IL_004e: ldloc.s V_4 IL_0050: call ""int?..ctor(int)"" - IL_0055: ldloc.s V_6 + IL_0055: ldloc.s V_5 IL_0057: constrained. ""T"" IL_005d: callvirt ""void IMoveable.this[int].set"" IL_0062: ret @@ -13856,14 +13758,12 @@ .locals init (T& V_0, T& V_2, int? V_3, int V_4, - T V_5, - int? V_6) + int? V_5) IL_0000: ldarg.0 IL_0001: stloc.2 - IL_0002: ldloca.s V_5 - IL_0004: initobj ""T"" - IL_000a: ldloc.s V_5 - IL_000c: box ""T"" + IL_0002: ldtoken ""T"" + IL_0007: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000c: call ""bool System.Type.IsValueType.get"" IL_0011: brtrue.s IL_001e IL_0013: ldloc.2 IL_0014: ldobj ""T"" @@ -13888,10 +13788,10 @@ .locals init (T& V_0, IL_0046: stloc.s V_4 IL_0048: ldloc.0 IL_0049: ldc.i4.1 - IL_004a: ldloca.s V_6 + IL_004a: ldloca.s V_5 IL_004c: ldloc.s V_4 IL_004e: call ""int?..ctor(int)"" - IL_0053: ldloc.s V_6 + IL_0053: ldloc.s V_5 IL_0055: constrained. ""T"" IL_005b: callvirt ""void IMoveable.this[int].set"" IL_0060: ret @@ -14193,10 +14093,9 @@ .maxstack 4 .locals init (int V_0, int? V_1, int V_2, - T V_3, - System.Runtime.CompilerServices.TaskAwaiter V_4, - int? V_5, - System.Exception V_6) + System.Runtime.CompilerServices.TaskAwaiter V_3, + int? V_4, + System.Exception V_5) IL_0000: ldarg.0 IL_0001: ldfld ""int Program.d__2.<>1__state"" IL_0006: stloc.0 @@ -14204,76 +14103,73 @@ .locals init (int V_0, { IL_0007: ldloc.0 IL_0008: brfalse IL_00ac - IL_000d: ldloca.s V_3 - IL_000f: initobj ""T"" - IL_0015: ldloc.3 - IL_0016: box ""T"" - IL_001b: brtrue.s IL_0029 - IL_001d: ldarg.0 + IL_000d: ldtoken ""T"" + IL_0012: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0017: call ""bool System.Type.IsValueType.get"" + IL_001c: brtrue.s IL_002a IL_001e: ldarg.0 - IL_001f: ldfld ""T Program.d__2.item"" - IL_0024: stfld ""T Program.d__2.<>7__wrap1"" - IL_0029: ldloca.s V_3 - IL_002b: initobj ""T"" - IL_0031: ldloc.3 - IL_0032: box ""T"" - IL_0037: brtrue.s IL_0041 - IL_0039: ldarg.0 - IL_003a: ldflda ""T Program.d__2.<>7__wrap1"" - IL_003f: br.s IL_0047 - IL_0041: ldarg.0 - IL_0042: ldflda ""T Program.d__2.item"" - IL_0047: ldc.i4.1 - IL_0048: constrained. ""T"" - IL_004e: callvirt ""int? IMoveable.this[int].get"" - IL_0053: stloc.1 - IL_0054: ldloca.s V_1 - IL_0056: call ""int int?.GetValueOrDefault()"" - IL_005b: stloc.2 - IL_005c: ldloca.s V_1 - IL_005e: call ""bool int?.HasValue.get"" - IL_0063: brtrue IL_0104 - IL_0068: ldarg.0 - IL_0069: ldflda ""T Program.d__2.item"" - IL_006e: call ""int Program.GetOffset(ref T)"" - IL_0073: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" - IL_0078: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_007d: stloc.s V_4 - IL_007f: ldloca.s V_4 - IL_0081: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_0086: brtrue.s IL_00c9 - IL_0088: ldarg.0 - IL_0089: ldc.i4.0 - IL_008a: dup - IL_008b: stloc.0 - IL_008c: stfld ""int Program.d__2.<>1__state"" - IL_0091: ldarg.0 - IL_0092: ldloc.s V_4 + IL_001f: ldarg.0 + IL_0020: ldfld ""T Program.d__2.item"" + IL_0025: stfld ""T Program.d__2.<>7__wrap1"" + IL_002a: ldtoken ""T"" + IL_002f: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0034: call ""bool System.Type.IsValueType.get"" + IL_0039: brtrue.s IL_0043 + IL_003b: ldarg.0 + IL_003c: ldflda ""T Program.d__2.<>7__wrap1"" + IL_0041: br.s IL_0049 + IL_0043: ldarg.0 + IL_0044: ldflda ""T Program.d__2.item"" + IL_0049: ldc.i4.1 + IL_004a: constrained. ""T"" + IL_0050: callvirt ""int? IMoveable.this[int].get"" + IL_0055: stloc.1 + IL_0056: ldloca.s V_1 + IL_0058: call ""int int?.GetValueOrDefault()"" + IL_005d: stloc.2 + IL_005e: ldloca.s V_1 + IL_0060: call ""bool int?.HasValue.get"" + IL_0065: brtrue IL_0104 + IL_006a: ldarg.0 + IL_006b: ldflda ""T Program.d__2.item"" + IL_0070: call ""int Program.GetOffset(ref T)"" + IL_0075: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" + IL_007a: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_007f: stloc.3 + IL_0080: ldloca.s V_3 + IL_0082: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_0087: brtrue.s IL_00c8 + IL_0089: ldarg.0 + IL_008a: ldc.i4.0 + IL_008b: dup + IL_008c: stloc.0 + IL_008d: stfld ""int Program.d__2.<>1__state"" + IL_0092: ldarg.0 + IL_0093: ldloc.3 IL_0094: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" IL_0099: ldarg.0 IL_009a: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_009f: ldloca.s V_4 + IL_009f: ldloca.s V_3 IL_00a1: ldarg.0 IL_00a2: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" IL_00a7: leave IL_013e IL_00ac: ldarg.0 IL_00ad: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_00b2: stloc.s V_4 - IL_00b4: ldarg.0 - IL_00b5: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_00ba: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_00c0: ldarg.0 - IL_00c1: ldc.i4.m1 - IL_00c2: dup - IL_00c3: stloc.0 - IL_00c4: stfld ""int Program.d__2.<>1__state"" - IL_00c9: ldloca.s V_4 - IL_00cb: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_00d0: stloc.2 - IL_00d1: ldloca.s V_3 - IL_00d3: initobj ""T"" - IL_00d9: ldloc.3 - IL_00da: box ""T"" + IL_00b2: stloc.3 + IL_00b3: ldarg.0 + IL_00b4: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_00b9: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_00bf: ldarg.0 + IL_00c0: ldc.i4.m1 + IL_00c1: dup + IL_00c2: stloc.0 + IL_00c3: stfld ""int Program.d__2.<>1__state"" + IL_00c8: ldloca.s V_3 + IL_00ca: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_00cf: stloc.2 + IL_00d0: ldtoken ""T"" + IL_00d5: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_00da: call ""bool System.Type.IsValueType.get"" IL_00df: brtrue.s IL_00e9 IL_00e1: ldarg.0 IL_00e2: ldflda ""T Program.d__2.<>7__wrap1"" @@ -14284,7 +14180,7 @@ .locals init (int V_0, IL_00f0: ldloc.2 IL_00f1: newobj ""int?..ctor(int)"" IL_00f6: dup - IL_00f7: stloc.s V_5 + IL_00f7: stloc.s V_4 IL_00f9: constrained. ""T"" IL_00ff: callvirt ""void IMoveable.this[int].set"" IL_0104: ldarg.0 @@ -14294,13 +14190,13 @@ .locals init (int V_0, } catch System.Exception { - IL_0112: stloc.s V_6 + IL_0112: stloc.s V_5 IL_0114: ldarg.0 IL_0115: ldc.i4.s -2 IL_0117: stfld ""int Program.d__2.<>1__state"" IL_011c: ldarg.0 IL_011d: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_0122: ldloc.s V_6 + IL_0122: ldloc.s V_5 IL_0124: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" IL_0129: leave.s IL_013e } @@ -14612,14 +14508,12 @@ .locals init (T& V_0, int V_3, int? V_4, int V_5, - T V_6, - int? V_7) + int? V_6) IL_0000: ldarga.s V_0 IL_0002: stloc.2 - IL_0003: ldloca.s V_6 - IL_0005: initobj ""T"" - IL_000b: ldloc.s V_6 - IL_000d: box ""T"" + IL_0003: ldtoken ""T"" + IL_0008: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000d: call ""bool System.Type.IsValueType.get"" IL_0012: brtrue.s IL_001f IL_0014: ldloc.2 IL_0015: ldobj ""T"" @@ -14647,10 +14541,10 @@ .locals init (T& V_0, IL_0051: stloc.s V_5 IL_0053: ldloc.0 IL_0054: ldloc.3 - IL_0055: ldloca.s V_7 + IL_0055: ldloca.s V_6 IL_0057: ldloc.s V_5 IL_0059: call ""int?..ctor(int)"" - IL_005e: ldloc.s V_7 + IL_005e: ldloc.s V_6 IL_0060: constrained. ""T"" IL_0066: callvirt ""void IMoveable.this[int].set"" IL_006b: ret @@ -14890,14 +14784,12 @@ .locals init (T& V_0, int V_3, int? V_4, int V_5, - T V_6, - int? V_7) + int? V_6) IL_0000: ldarg.0 IL_0001: stloc.2 - IL_0002: ldloca.s V_6 - IL_0004: initobj ""T"" - IL_000a: ldloc.s V_6 - IL_000c: box ""T"" + IL_0002: ldtoken ""T"" + IL_0007: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000c: call ""bool System.Type.IsValueType.get"" IL_0011: brtrue.s IL_001e IL_0013: ldloc.2 IL_0014: ldobj ""T"" @@ -14925,10 +14817,10 @@ .locals init (T& V_0, IL_004e: stloc.s V_5 IL_0050: ldloc.0 IL_0051: ldloc.3 - IL_0052: ldloca.s V_7 + IL_0052: ldloca.s V_6 IL_0054: ldloc.s V_5 IL_0056: call ""int?..ctor(int)"" - IL_005b: ldloc.s V_7 + IL_005b: ldloc.s V_6 IL_005d: constrained. ""T"" IL_0063: callvirt ""void IMoveable.this[int].set"" IL_0068: ret @@ -15241,10 +15133,9 @@ .maxstack 4 .locals init (int V_0, int? V_1, int V_2, - T V_3, - System.Runtime.CompilerServices.TaskAwaiter V_4, - int? V_5, - System.Exception V_6) + System.Runtime.CompilerServices.TaskAwaiter V_3, + int? V_4, + System.Exception V_5) IL_0000: ldarg.0 IL_0001: ldfld ""int Program.d__2.<>1__state"" IL_0006: stloc.0 @@ -15252,82 +15143,79 @@ .locals init (int V_0, { IL_0007: ldloc.0 IL_0008: brfalse IL_00c2 - IL_000d: ldloca.s V_3 - IL_000f: initobj ""T"" - IL_0015: ldloc.3 - IL_0016: box ""T"" - IL_001b: brtrue.s IL_0029 - IL_001d: ldarg.0 + IL_000d: ldtoken ""T"" + IL_0012: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0017: call ""bool System.Type.IsValueType.get"" + IL_001c: brtrue.s IL_002a IL_001e: ldarg.0 - IL_001f: ldfld ""T Program.d__2.item"" - IL_0024: stfld ""T Program.d__2.<>7__wrap1"" - IL_0029: ldarg.0 + IL_001f: ldarg.0 + IL_0020: ldfld ""T Program.d__2.item"" + IL_0025: stfld ""T Program.d__2.<>7__wrap1"" IL_002a: ldarg.0 - IL_002b: ldflda ""T Program.d__2.item"" - IL_0030: call ""int Program.GetOffset(ref T)"" - IL_0035: stfld ""int Program.d__2.<>7__wrap2"" - IL_003a: ldloca.s V_3 - IL_003c: initobj ""T"" - IL_0042: ldloc.3 - IL_0043: box ""T"" - IL_0048: brtrue.s IL_0052 - IL_004a: ldarg.0 - IL_004b: ldflda ""T Program.d__2.<>7__wrap1"" - IL_0050: br.s IL_0058 - IL_0052: ldarg.0 - IL_0053: ldflda ""T Program.d__2.item"" - IL_0058: ldarg.0 - IL_0059: ldfld ""int Program.d__2.<>7__wrap2"" - IL_005e: constrained. ""T"" - IL_0064: callvirt ""int? IMoveable.this[int].get"" - IL_0069: stloc.1 - IL_006a: ldloca.s V_1 - IL_006c: call ""int int?.GetValueOrDefault()"" - IL_0071: stloc.2 - IL_0072: ldloca.s V_1 - IL_0074: call ""bool int?.HasValue.get"" - IL_0079: brtrue IL_011f - IL_007e: ldarg.0 - IL_007f: ldflda ""T Program.d__2.item"" - IL_0084: call ""int Program.GetOffset(ref T)"" - IL_0089: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" - IL_008e: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_0093: stloc.s V_4 - IL_0095: ldloca.s V_4 - IL_0097: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_009c: brtrue.s IL_00df - IL_009e: ldarg.0 - IL_009f: ldc.i4.0 - IL_00a0: dup - IL_00a1: stloc.0 - IL_00a2: stfld ""int Program.d__2.<>1__state"" - IL_00a7: ldarg.0 - IL_00a8: ldloc.s V_4 + IL_002b: ldarg.0 + IL_002c: ldflda ""T Program.d__2.item"" + IL_0031: call ""int Program.GetOffset(ref T)"" + IL_0036: stfld ""int Program.d__2.<>7__wrap2"" + IL_003b: ldtoken ""T"" + IL_0040: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0045: call ""bool System.Type.IsValueType.get"" + IL_004a: brtrue.s IL_0054 + IL_004c: ldarg.0 + IL_004d: ldflda ""T Program.d__2.<>7__wrap1"" + IL_0052: br.s IL_005a + IL_0054: ldarg.0 + IL_0055: ldflda ""T Program.d__2.item"" + IL_005a: ldarg.0 + IL_005b: ldfld ""int Program.d__2.<>7__wrap2"" + IL_0060: constrained. ""T"" + IL_0066: callvirt ""int? IMoveable.this[int].get"" + IL_006b: stloc.1 + IL_006c: ldloca.s V_1 + IL_006e: call ""int int?.GetValueOrDefault()"" + IL_0073: stloc.2 + IL_0074: ldloca.s V_1 + IL_0076: call ""bool int?.HasValue.get"" + IL_007b: brtrue IL_011f + IL_0080: ldarg.0 + IL_0081: ldflda ""T Program.d__2.item"" + IL_0086: call ""int Program.GetOffset(ref T)"" + IL_008b: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" + IL_0090: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_0095: stloc.3 + IL_0096: ldloca.s V_3 + IL_0098: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_009d: brtrue.s IL_00de + IL_009f: ldarg.0 + IL_00a0: ldc.i4.0 + IL_00a1: dup + IL_00a2: stloc.0 + IL_00a3: stfld ""int Program.d__2.<>1__state"" + IL_00a8: ldarg.0 + IL_00a9: ldloc.3 IL_00aa: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" IL_00af: ldarg.0 IL_00b0: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_00b5: ldloca.s V_4 + IL_00b5: ldloca.s V_3 IL_00b7: ldarg.0 IL_00b8: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" IL_00bd: leave IL_0159 IL_00c2: ldarg.0 IL_00c3: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_00c8: stloc.s V_4 - IL_00ca: ldarg.0 - IL_00cb: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_00d0: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_00d6: ldarg.0 - IL_00d7: ldc.i4.m1 - IL_00d8: dup - IL_00d9: stloc.0 - IL_00da: stfld ""int Program.d__2.<>1__state"" - IL_00df: ldloca.s V_4 - IL_00e1: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_00e6: stloc.2 - IL_00e7: ldloca.s V_3 - IL_00e9: initobj ""T"" - IL_00ef: ldloc.3 - IL_00f0: box ""T"" + IL_00c8: stloc.3 + IL_00c9: ldarg.0 + IL_00ca: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_00cf: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_00d5: ldarg.0 + IL_00d6: ldc.i4.m1 + IL_00d7: dup + IL_00d8: stloc.0 + IL_00d9: stfld ""int Program.d__2.<>1__state"" + IL_00de: ldloca.s V_3 + IL_00e0: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_00e5: stloc.2 + IL_00e6: ldtoken ""T"" + IL_00eb: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_00f0: call ""bool System.Type.IsValueType.get"" IL_00f5: brtrue.s IL_00ff IL_00f7: ldarg.0 IL_00f8: ldflda ""T Program.d__2.<>7__wrap1"" @@ -15339,7 +15227,7 @@ .locals init (int V_0, IL_010b: ldloc.2 IL_010c: newobj ""int?..ctor(int)"" IL_0111: dup - IL_0112: stloc.s V_5 + IL_0112: stloc.s V_4 IL_0114: constrained. ""T"" IL_011a: callvirt ""void IMoveable.this[int].set"" IL_011f: ldarg.0 @@ -15349,13 +15237,13 @@ .locals init (int V_0, } catch System.Exception { - IL_012d: stloc.s V_6 + IL_012d: stloc.s V_5 IL_012f: ldarg.0 IL_0130: ldc.i4.s -2 IL_0132: stfld ""int Program.d__2.<>1__state"" IL_0137: ldarg.0 IL_0138: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_013d: ldloc.s V_6 + IL_013d: ldloc.s V_5 IL_013f: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" IL_0144: leave.s IL_0159 } @@ -15747,10 +15635,9 @@ .locals init (int V_0, int V_1, int? V_2, int V_3, - T V_4, - System.Runtime.CompilerServices.TaskAwaiter V_5, - int? V_6, - System.Exception V_7) + System.Runtime.CompilerServices.TaskAwaiter V_4, + int? V_5, + System.Exception V_6) IL_0000: ldarg.0 IL_0001: ldfld ""int Program.d__2.<>1__state"" IL_0006: stloc.0 @@ -15758,10 +15645,9 @@ .locals init (int V_0, { IL_0007: ldloc.0 IL_0008: brfalse.s IL_006b - IL_000a: ldloca.s V_4 - IL_000c: initobj ""T"" - IL_0012: ldloc.s V_4 - IL_0014: box ""T"" + IL_000a: ldtoken ""T"" + IL_000f: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0014: call ""bool System.Type.IsValueType.get"" IL_0019: brtrue.s IL_0027 IL_001b: ldarg.0 IL_001c: ldarg.0 @@ -15772,8 +15658,8 @@ .locals init (int V_0, IL_002d: call ""int Program.GetOffset(ref T)"" IL_0032: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" IL_0037: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_003c: stloc.s V_5 - IL_003e: ldloca.s V_5 + IL_003c: stloc.s V_4 + IL_003e: ldloca.s V_4 IL_0040: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" IL_0045: brtrue.s IL_0088 IL_0047: ldarg.0 @@ -15782,17 +15668,17 @@ .locals init (int V_0, IL_004a: stloc.0 IL_004b: stfld ""int Program.d__2.<>1__state"" IL_0050: ldarg.0 - IL_0051: ldloc.s V_5 + IL_0051: ldloc.s V_4 IL_0053: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" IL_0058: ldarg.0 IL_0059: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_005e: ldloca.s V_5 + IL_005e: ldloca.s V_4 IL_0060: ldarg.0 IL_0061: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" IL_0066: leave IL_0147 IL_006b: ldarg.0 IL_006c: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_0071: stloc.s V_5 + IL_0071: stloc.s V_4 IL_0073: ldarg.0 IL_0074: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" IL_0079: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" @@ -15801,13 +15687,12 @@ .locals init (int V_0, IL_0081: dup IL_0082: stloc.0 IL_0083: stfld ""int Program.d__2.<>1__state"" - IL_0088: ldloca.s V_5 + IL_0088: ldloca.s V_4 IL_008a: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" IL_008f: stloc.1 - IL_0090: ldloca.s V_4 - IL_0092: initobj ""T"" - IL_0098: ldloc.s V_4 - IL_009a: box ""T"" + IL_0090: ldtoken ""T"" + IL_0095: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_009a: call ""bool System.Type.IsValueType.get"" IL_009f: brtrue.s IL_00a9 IL_00a1: ldarg.0 IL_00a2: ldflda ""T Program.d__2.<>7__wrap1"" @@ -15828,10 +15713,9 @@ .locals init (int V_0, IL_00ce: ldflda ""T Program.d__2.item"" IL_00d3: call ""int Program.GetOffset(ref T)"" IL_00d8: stloc.3 - IL_00d9: ldloca.s V_4 - IL_00db: initobj ""T"" - IL_00e1: ldloc.s V_4 - IL_00e3: box ""T"" + IL_00d9: ldtoken ""T"" + IL_00de: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_00e3: call ""bool System.Type.IsValueType.get"" IL_00e8: brtrue.s IL_00f2 IL_00ea: ldarg.0 IL_00eb: ldflda ""T Program.d__2.<>7__wrap1"" @@ -15842,7 +15726,7 @@ .locals init (int V_0, IL_00f9: ldloc.3 IL_00fa: newobj ""int?..ctor(int)"" IL_00ff: dup - IL_0100: stloc.s V_6 + IL_0100: stloc.s V_5 IL_0102: constrained. ""T"" IL_0108: callvirt ""void IMoveable.this[int].set"" IL_010d: ldarg.0 @@ -15852,13 +15736,13 @@ .locals init (int V_0, } catch System.Exception { - IL_011b: stloc.s V_7 + IL_011b: stloc.s V_6 IL_011d: ldarg.0 IL_011e: ldc.i4.s -2 IL_0120: stfld ""int Program.d__2.<>1__state"" IL_0125: ldarg.0 IL_0126: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_012b: ldloc.s V_7 + IL_012b: ldloc.s V_6 IL_012d: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" IL_0132: leave.s IL_0147 } @@ -16289,10 +16173,9 @@ .locals init (int V_0, int V_1, int? V_2, int V_3, - T V_4, - System.Runtime.CompilerServices.TaskAwaiter V_5, - int? V_6, - System.Exception V_7) + System.Runtime.CompilerServices.TaskAwaiter V_4, + int? V_5, + System.Exception V_6) IL_0000: ldarg.0 IL_0001: ldfld ""int Program.d__2.<>1__state"" IL_0006: stloc.0 @@ -16303,10 +16186,9 @@ .locals init (int V_0, IL_000a: ldloc.0 IL_000b: ldc.i4.1 IL_000c: beq IL_0127 - IL_0011: ldloca.s V_4 - IL_0013: initobj ""T"" - IL_0019: ldloc.s V_4 - IL_001b: box ""T"" + IL_0011: ldtoken ""T"" + IL_0016: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_001b: call ""bool System.Type.IsValueType.get"" IL_0020: brtrue.s IL_002e IL_0022: ldarg.0 IL_0023: ldarg.0 @@ -16317,8 +16199,8 @@ .locals init (int V_0, IL_0034: call ""int Program.GetOffset(ref T)"" IL_0039: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" IL_003e: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_0043: stloc.s V_5 - IL_0045: ldloca.s V_5 + IL_0043: stloc.s V_4 + IL_0045: ldloca.s V_4 IL_0047: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" IL_004c: brtrue.s IL_008f IL_004e: ldarg.0 @@ -16327,17 +16209,17 @@ .locals init (int V_0, IL_0051: stloc.0 IL_0052: stfld ""int Program.d__2.<>1__state"" IL_0057: ldarg.0 - IL_0058: ldloc.s V_5 + IL_0058: ldloc.s V_4 IL_005a: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" IL_005f: ldarg.0 IL_0060: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_0065: ldloca.s V_5 + IL_0065: ldloca.s V_4 IL_0067: ldarg.0 IL_0068: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" IL_006d: leave IL_01bf IL_0072: ldarg.0 IL_0073: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_0078: stloc.s V_5 + IL_0078: stloc.s V_4 IL_007a: ldarg.0 IL_007b: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" IL_0080: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" @@ -16346,16 +16228,15 @@ .locals init (int V_0, IL_0088: dup IL_0089: stloc.0 IL_008a: stfld ""int Program.d__2.<>1__state"" - IL_008f: ldloca.s V_5 + IL_008f: ldloca.s V_4 IL_0091: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" IL_0096: stloc.1 IL_0097: ldarg.0 IL_0098: ldloc.1 IL_0099: stfld ""int Program.d__2.<>7__wrap2"" - IL_009e: ldloca.s V_4 - IL_00a0: initobj ""T"" - IL_00a6: ldloc.s V_4 - IL_00a8: box ""T"" + IL_009e: ldtoken ""T"" + IL_00a3: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_00a8: call ""bool System.Type.IsValueType.get"" IL_00ad: brtrue.s IL_00b7 IL_00af: ldarg.0 IL_00b0: ldflda ""T Program.d__2.<>7__wrap1"" @@ -16378,8 +16259,8 @@ .locals init (int V_0, IL_00e9: call ""int Program.GetOffset(ref T)"" IL_00ee: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" IL_00f3: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_00f8: stloc.s V_5 - IL_00fa: ldloca.s V_5 + IL_00f8: stloc.s V_4 + IL_00fa: ldloca.s V_4 IL_00fc: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" IL_0101: brtrue.s IL_0144 IL_0103: ldarg.0 @@ -16388,17 +16269,17 @@ .locals init (int V_0, IL_0106: stloc.0 IL_0107: stfld ""int Program.d__2.<>1__state"" IL_010c: ldarg.0 - IL_010d: ldloc.s V_5 + IL_010d: ldloc.s V_4 IL_010f: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" IL_0114: ldarg.0 IL_0115: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_011a: ldloca.s V_5 + IL_011a: ldloca.s V_4 IL_011c: ldarg.0 IL_011d: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" IL_0122: leave IL_01bf IL_0127: ldarg.0 IL_0128: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_012d: stloc.s V_5 + IL_012d: stloc.s V_4 IL_012f: ldarg.0 IL_0130: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" IL_0135: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" @@ -16407,13 +16288,12 @@ .locals init (int V_0, IL_013d: dup IL_013e: stloc.0 IL_013f: stfld ""int Program.d__2.<>1__state"" - IL_0144: ldloca.s V_5 + IL_0144: ldloca.s V_4 IL_0146: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" IL_014b: stloc.3 - IL_014c: ldloca.s V_4 - IL_014e: initobj ""T"" - IL_0154: ldloc.s V_4 - IL_0156: box ""T"" + IL_014c: ldtoken ""T"" + IL_0151: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0156: call ""bool System.Type.IsValueType.get"" IL_015b: brtrue.s IL_0165 IL_015d: ldarg.0 IL_015e: ldflda ""T Program.d__2.<>7__wrap1"" @@ -16425,7 +16305,7 @@ .locals init (int V_0, IL_0171: ldloc.3 IL_0172: newobj ""int?..ctor(int)"" IL_0177: dup - IL_0178: stloc.s V_6 + IL_0178: stloc.s V_5 IL_017a: constrained. ""T"" IL_0180: callvirt ""void IMoveable.this[int].set"" IL_0185: ldarg.0 @@ -16435,13 +16315,13 @@ .locals init (int V_0, } catch System.Exception { - IL_0193: stloc.s V_7 + IL_0193: stloc.s V_6 IL_0195: ldarg.0 IL_0196: ldc.i4.s -2 IL_0198: stfld ""int Program.d__2.<>1__state"" IL_019d: ldarg.0 IL_019e: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_01a3: ldloc.s V_7 + IL_01a3: ldloc.s V_6 IL_01a5: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" IL_01aa: leave.s IL_01bf } @@ -16765,32 +16645,30 @@ .locals init (T V_0, verifier.VerifyIL("Program.Shift2", @" { - // Code size 52 (0x34) + // Code size 53 (0x35) .maxstack 2 .locals init (T V_0, T& V_1, - T V_2, - int V_3) + int V_2) IL_0000: ldarga.s V_0 IL_0002: stloc.1 - IL_0003: ldloca.s V_2 - IL_0005: initobj ""T"" - IL_000b: ldloc.2 - IL_000c: box ""T"" - IL_0011: brtrue.s IL_001e - IL_0013: ldloc.1 - IL_0014: ldobj ""T"" - IL_0019: stloc.0 - IL_001a: ldloca.s V_0 - IL_001c: br.s IL_001f - IL_001e: ldloc.1 - IL_001f: ldarga.s V_0 - IL_0021: call ""int Program.GetOffset(ref T)"" - IL_0026: stloc.3 - IL_0027: ldloc.3 - IL_0028: constrained. ""T"" - IL_002e: callvirt ""void IMoveable.Position.set"" - IL_0033: ret + IL_0003: ldtoken ""T"" + IL_0008: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000d: call ""bool System.Type.IsValueType.get"" + IL_0012: brtrue.s IL_001f + IL_0014: ldloc.1 + IL_0015: ldobj ""T"" + IL_001a: stloc.0 + IL_001b: ldloca.s V_0 + IL_001d: br.s IL_0020 + IL_001f: ldloc.1 + IL_0020: ldarga.s V_0 + IL_0022: call ""int Program.GetOffset(ref T)"" + IL_0027: stloc.2 + IL_0028: ldloc.2 + IL_0029: constrained. ""T"" + IL_002f: callvirt ""void IMoveable.Position.set"" + IL_0034: ret } "); } @@ -16967,32 +16845,30 @@ .locals init (T V_0, verifier.VerifyIL("Program.Shift2", @" { - // Code size 50 (0x32) + // Code size 51 (0x33) .maxstack 2 .locals init (T V_0, T& V_1, - T V_2, - int V_3) + int V_2) IL_0000: ldarg.0 IL_0001: stloc.1 - IL_0002: ldloca.s V_2 - IL_0004: initobj ""T"" - IL_000a: ldloc.2 - IL_000b: box ""T"" - IL_0010: brtrue.s IL_001d - IL_0012: ldloc.1 - IL_0013: ldobj ""T"" - IL_0018: stloc.0 - IL_0019: ldloca.s V_0 - IL_001b: br.s IL_001e - IL_001d: ldloc.1 - IL_001e: ldarg.0 - IL_001f: call ""int Program.GetOffset(ref T)"" - IL_0024: stloc.3 - IL_0025: ldloc.3 - IL_0026: constrained. ""T"" - IL_002c: callvirt ""void IMoveable.Position.set"" - IL_0031: ret + IL_0002: ldtoken ""T"" + IL_0007: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000c: call ""bool System.Type.IsValueType.get"" + IL_0011: brtrue.s IL_001e + IL_0013: ldloc.1 + IL_0014: ldobj ""T"" + IL_0019: stloc.0 + IL_001a: ldloca.s V_0 + IL_001c: br.s IL_001f + IL_001e: ldloc.1 + IL_001f: ldarg.0 + IL_0020: call ""int Program.GetOffset(ref T)"" + IL_0025: stloc.2 + IL_0026: ldloc.2 + IL_0027: constrained. ""T"" + IL_002d: callvirt ""void IMoveable.Position.set"" + IL_0032: ret } "); } @@ -17248,89 +17124,86 @@ .locals init (int V_0, .maxstack 3 .locals init (int V_0, int V_1, - T V_2, - System.Runtime.CompilerServices.TaskAwaiter V_3, - System.Exception V_4) + System.Runtime.CompilerServices.TaskAwaiter V_2, + System.Exception V_3) IL_0000: ldarg.0 IL_0001: ldfld ""int Program.d__2.<>1__state"" IL_0006: stloc.0 .try { IL_0007: ldloc.0 - IL_0008: brfalse.s IL_0068 - IL_000a: ldloca.s V_2 - IL_000c: initobj ""T"" - IL_0012: ldloc.2 - IL_0013: box ""T"" - IL_0018: brtrue.s IL_0026 - IL_001a: ldarg.0 + IL_0008: brfalse.s IL_0069 + IL_000a: ldtoken ""T"" + IL_000f: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0014: call ""bool System.Type.IsValueType.get"" + IL_0019: brtrue.s IL_0027 IL_001b: ldarg.0 - IL_001c: ldfld ""T Program.d__2.item"" - IL_0021: stfld ""T Program.d__2.<>7__wrap1"" - IL_0026: ldarg.0 - IL_0027: ldflda ""T Program.d__2.item"" - IL_002c: call ""int Program.GetOffset(ref T)"" - IL_0031: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" - IL_0036: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_003b: stloc.3 - IL_003c: ldloca.s V_3 - IL_003e: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_0043: brtrue.s IL_0084 - IL_0045: ldarg.0 - IL_0046: ldc.i4.0 - IL_0047: dup - IL_0048: stloc.0 - IL_0049: stfld ""int Program.d__2.<>1__state"" - IL_004e: ldarg.0 - IL_004f: ldloc.3 - IL_0050: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_0055: ldarg.0 - IL_0056: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_005b: ldloca.s V_3 - IL_005d: ldarg.0 - IL_005e: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" - IL_0063: leave IL_00f0 - IL_0068: ldarg.0 - IL_0069: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_006e: stloc.3 - IL_006f: ldarg.0 - IL_0070: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_0075: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_007b: ldarg.0 - IL_007c: ldc.i4.m1 - IL_007d: dup - IL_007e: stloc.0 - IL_007f: stfld ""int Program.d__2.<>1__state"" - IL_0084: ldloca.s V_3 - IL_0086: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_008b: stloc.1 - IL_008c: ldloca.s V_2 - IL_008e: initobj ""T"" - IL_0094: ldloc.2 - IL_0095: box ""T"" - IL_009a: brtrue.s IL_00a4 - IL_009c: ldarg.0 - IL_009d: ldflda ""T Program.d__2.<>7__wrap1"" - IL_00a2: br.s IL_00aa - IL_00a4: ldarg.0 - IL_00a5: ldflda ""T Program.d__2.item"" - IL_00aa: ldloc.1 - IL_00ab: constrained. ""T"" - IL_00b1: callvirt ""void IMoveable.Position.set"" - IL_00b6: ldarg.0 - IL_00b7: ldflda ""T Program.d__2.<>7__wrap1"" - IL_00bc: initobj ""T"" - IL_00c2: leave.s IL_00dd + IL_001c: ldarg.0 + IL_001d: ldfld ""T Program.d__2.item"" + IL_0022: stfld ""T Program.d__2.<>7__wrap1"" + IL_0027: ldarg.0 + IL_0028: ldflda ""T Program.d__2.item"" + IL_002d: call ""int Program.GetOffset(ref T)"" + IL_0032: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" + IL_0037: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_003c: stloc.2 + IL_003d: ldloca.s V_2 + IL_003f: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_0044: brtrue.s IL_0085 + IL_0046: ldarg.0 + IL_0047: ldc.i4.0 + IL_0048: dup + IL_0049: stloc.0 + IL_004a: stfld ""int Program.d__2.<>1__state"" + IL_004f: ldarg.0 + IL_0050: ldloc.2 + IL_0051: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_0056: ldarg.0 + IL_0057: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_005c: ldloca.s V_2 + IL_005e: ldarg.0 + IL_005f: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" + IL_0064: leave IL_00f0 + IL_0069: ldarg.0 + IL_006a: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_006f: stloc.2 + IL_0070: ldarg.0 + IL_0071: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_0076: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_007c: ldarg.0 + IL_007d: ldc.i4.m1 + IL_007e: dup + IL_007f: stloc.0 + IL_0080: stfld ""int Program.d__2.<>1__state"" + IL_0085: ldloca.s V_2 + IL_0087: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_008c: stloc.1 + IL_008d: ldtoken ""T"" + IL_0092: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0097: call ""bool System.Type.IsValueType.get"" + IL_009c: brtrue.s IL_00a6 + IL_009e: ldarg.0 + IL_009f: ldflda ""T Program.d__2.<>7__wrap1"" + IL_00a4: br.s IL_00ac + IL_00a6: ldarg.0 + IL_00a7: ldflda ""T Program.d__2.item"" + IL_00ac: ldloc.1 + IL_00ad: constrained. ""T"" + IL_00b3: callvirt ""void IMoveable.Position.set"" + IL_00b8: ldarg.0 + IL_00b9: ldflda ""T Program.d__2.<>7__wrap1"" + IL_00be: initobj ""T"" + IL_00c4: leave.s IL_00dd } catch System.Exception { - IL_00c4: stloc.s V_4 - IL_00c6: ldarg.0 - IL_00c7: ldc.i4.s -2 - IL_00c9: stfld ""int Program.d__2.<>1__state"" - IL_00ce: ldarg.0 - IL_00cf: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_00d4: ldloc.s V_4 + IL_00c6: stloc.3 + IL_00c7: ldarg.0 + IL_00c8: ldc.i4.s -2 + IL_00ca: stfld ""int Program.d__2.<>1__state"" + IL_00cf: ldarg.0 + IL_00d0: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_00d5: ldloc.3 IL_00d6: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" IL_00db: leave.s IL_00f0 } @@ -17605,19 +17478,17 @@ .locals init (T V_0, verifier.VerifyIL("Program.Shift2", @" { - // Code size 69 (0x45) + // Code size 69 (0x45) .maxstack 3 .locals init (T& V_0, T V_1, T& V_2, - int V_3, - T V_4) + int V_3) IL_0000: ldarga.s V_0 IL_0002: stloc.2 - IL_0003: ldloca.s V_4 - IL_0005: initobj ""T"" - IL_000b: ldloc.s V_4 - IL_000d: box ""T"" + IL_0003: ldtoken ""T"" + IL_0008: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000d: call ""bool System.Type.IsValueType.get"" IL_0012: brtrue.s IL_001f IL_0014: ldloc.2 IL_0015: ldobj ""T"" @@ -17854,14 +17725,12 @@ .maxstack 3 .locals init (T& V_0, T V_1, T& V_2, - int V_3, - T V_4) + int V_3) IL_0000: ldarg.0 IL_0001: stloc.2 - IL_0002: ldloca.s V_4 - IL_0004: initobj ""T"" - IL_000a: ldloc.s V_4 - IL_000c: box ""T"" + IL_0002: ldtoken ""T"" + IL_0007: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000c: call ""bool System.Type.IsValueType.get"" IL_0011: brtrue.s IL_001e IL_0013: ldloc.2 IL_0014: ldobj ""T"" @@ -18169,117 +18038,113 @@ .locals init (int V_0, verifier.VerifyIL("Program.d__2.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @" { - // Code size 284 (0x11c) + // Code size 285 (0x11d) .maxstack 3 .locals init (int V_0, int V_1, - T V_2, - System.Runtime.CompilerServices.TaskAwaiter V_3, - System.Exception V_4) + System.Runtime.CompilerServices.TaskAwaiter V_2, + System.Exception V_3) IL_0000: ldarg.0 IL_0001: ldfld ""int Program.d__2.<>1__state"" IL_0006: stloc.0 .try { IL_0007: ldloc.0 - IL_0008: brfalse.s IL_0068 - IL_000a: ldloca.s V_2 - IL_000c: initobj ""T"" - IL_0012: ldloc.2 - IL_0013: box ""T"" - IL_0018: brtrue.s IL_0026 - IL_001a: ldarg.0 + IL_0008: brfalse.s IL_0069 + IL_000a: ldtoken ""T"" + IL_000f: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0014: call ""bool System.Type.IsValueType.get"" + IL_0019: brtrue.s IL_0027 IL_001b: ldarg.0 - IL_001c: ldfld ""T Program.d__2.item"" - IL_0021: stfld ""T Program.d__2.<>7__wrap1"" - IL_0026: ldarg.0 - IL_0027: ldflda ""T Program.d__2.item"" - IL_002c: call ""int Program.GetOffset(ref T)"" - IL_0031: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" - IL_0036: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_003b: stloc.3 - IL_003c: ldloca.s V_3 - IL_003e: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_0043: brtrue.s IL_0084 - IL_0045: ldarg.0 - IL_0046: ldc.i4.0 - IL_0047: dup - IL_0048: stloc.0 - IL_0049: stfld ""int Program.d__2.<>1__state"" - IL_004e: ldarg.0 - IL_004f: ldloc.3 - IL_0050: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_0055: ldarg.0 - IL_0056: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_005b: ldloca.s V_3 - IL_005d: ldarg.0 - IL_005e: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" - IL_0063: leave IL_011b - IL_0068: ldarg.0 - IL_0069: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_006e: stloc.3 - IL_006f: ldarg.0 - IL_0070: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_0075: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_007b: ldarg.0 - IL_007c: ldc.i4.m1 - IL_007d: dup - IL_007e: stloc.0 - IL_007f: stfld ""int Program.d__2.<>1__state"" - IL_0084: ldloca.s V_3 - IL_0086: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_008b: stloc.1 - IL_008c: ldloca.s V_2 - IL_008e: initobj ""T"" - IL_0094: ldloc.2 - IL_0095: box ""T"" - IL_009a: brtrue.s IL_00a4 - IL_009c: ldarg.0 - IL_009d: ldflda ""T Program.d__2.<>7__wrap1"" - IL_00a2: br.s IL_00aa - IL_00a4: ldarg.0 - IL_00a5: ldflda ""T Program.d__2.item"" - IL_00aa: ldloca.s V_2 - IL_00ac: initobj ""T"" - IL_00b2: ldloc.2 - IL_00b3: box ""T"" - IL_00b8: brtrue.s IL_00c2 - IL_00ba: ldarg.0 - IL_00bb: ldflda ""T Program.d__2.<>7__wrap1"" - IL_00c0: br.s IL_00c8 - IL_00c2: ldarg.0 - IL_00c3: ldflda ""T Program.d__2.item"" - IL_00c8: constrained. ""T"" - IL_00ce: callvirt ""int IMoveable.Length.get"" - IL_00d3: ldloc.1 - IL_00d4: sub - IL_00d5: constrained. ""T"" - IL_00db: callvirt ""int IMoveable.this[int].get"" - IL_00e0: pop - IL_00e1: ldarg.0 - IL_00e2: ldflda ""T Program.d__2.<>7__wrap1"" - IL_00e7: initobj ""T"" - IL_00ed: leave.s IL_0108 + IL_001c: ldarg.0 + IL_001d: ldfld ""T Program.d__2.item"" + IL_0022: stfld ""T Program.d__2.<>7__wrap1"" + IL_0027: ldarg.0 + IL_0028: ldflda ""T Program.d__2.item"" + IL_002d: call ""int Program.GetOffset(ref T)"" + IL_0032: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" + IL_0037: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_003c: stloc.2 + IL_003d: ldloca.s V_2 + IL_003f: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_0044: brtrue.s IL_0085 + IL_0046: ldarg.0 + IL_0047: ldc.i4.0 + IL_0048: dup + IL_0049: stloc.0 + IL_004a: stfld ""int Program.d__2.<>1__state"" + IL_004f: ldarg.0 + IL_0050: ldloc.2 + IL_0051: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_0056: ldarg.0 + IL_0057: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_005c: ldloca.s V_2 + IL_005e: ldarg.0 + IL_005f: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" + IL_0064: leave IL_011c + IL_0069: ldarg.0 + IL_006a: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_006f: stloc.2 + IL_0070: ldarg.0 + IL_0071: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_0076: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_007c: ldarg.0 + IL_007d: ldc.i4.m1 + IL_007e: dup + IL_007f: stloc.0 + IL_0080: stfld ""int Program.d__2.<>1__state"" + IL_0085: ldloca.s V_2 + IL_0087: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_008c: stloc.1 + IL_008d: ldtoken ""T"" + IL_0092: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0097: call ""bool System.Type.IsValueType.get"" + IL_009c: brtrue.s IL_00a6 + IL_009e: ldarg.0 + IL_009f: ldflda ""T Program.d__2.<>7__wrap1"" + IL_00a4: br.s IL_00ac + IL_00a6: ldarg.0 + IL_00a7: ldflda ""T Program.d__2.item"" + IL_00ac: ldtoken ""T"" + IL_00b1: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_00b6: call ""bool System.Type.IsValueType.get"" + IL_00bb: brtrue.s IL_00c5 + IL_00bd: ldarg.0 + IL_00be: ldflda ""T Program.d__2.<>7__wrap1"" + IL_00c3: br.s IL_00cb + IL_00c5: ldarg.0 + IL_00c6: ldflda ""T Program.d__2.item"" + IL_00cb: constrained. ""T"" + IL_00d1: callvirt ""int IMoveable.Length.get"" + IL_00d6: ldloc.1 + IL_00d7: sub + IL_00d8: constrained. ""T"" + IL_00de: callvirt ""int IMoveable.this[int].get"" + IL_00e3: pop + IL_00e4: ldarg.0 + IL_00e5: ldflda ""T Program.d__2.<>7__wrap1"" + IL_00ea: initobj ""T"" + IL_00f0: leave.s IL_0109 } catch System.Exception { - IL_00ef: stloc.s V_4 - IL_00f1: ldarg.0 - IL_00f2: ldc.i4.s -2 - IL_00f4: stfld ""int Program.d__2.<>1__state"" - IL_00f9: ldarg.0 - IL_00fa: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_00ff: ldloc.s V_4 - IL_0101: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" - IL_0106: leave.s IL_011b + IL_00f2: stloc.3 + IL_00f3: ldarg.0 + IL_00f4: ldc.i4.s -2 + IL_00f6: stfld ""int Program.d__2.<>1__state"" + IL_00fb: ldarg.0 + IL_00fc: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_0101: ldloc.3 + IL_0102: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" + IL_0107: leave.s IL_011c } - IL_0108: ldarg.0 - IL_0109: ldc.i4.s -2 - IL_010b: stfld ""int Program.d__2.<>1__state"" - IL_0110: ldarg.0 - IL_0111: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_0116: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" - IL_011b: ret + IL_0109: ldarg.0 + IL_010a: ldc.i4.s -2 + IL_010c: stfld ""int Program.d__2.<>1__state"" + IL_0111: ldarg.0 + IL_0112: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_0117: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" + IL_011c: ret } "); } @@ -18578,14 +18443,12 @@ .locals init (T& V_0, T V_1, T& V_2, int V_3, - int V_4, - T V_5) + int V_4) IL_0000: ldarga.s V_0 IL_0002: stloc.2 - IL_0003: ldloca.s V_5 - IL_0005: initobj ""T"" - IL_000b: ldloc.s V_5 - IL_000d: box ""T"" + IL_0003: ldtoken ""T"" + IL_0008: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000d: call ""bool System.Type.IsValueType.get"" IL_0012: brtrue.s IL_001f IL_0014: ldloc.2 IL_0015: ldobj ""T"" @@ -18853,14 +18716,12 @@ .locals init (T& V_0, T V_1, T& V_2, int V_3, - int V_4, - T V_5) + int V_4) IL_0000: ldarg.0 IL_0001: stloc.2 - IL_0002: ldloca.s V_5 - IL_0004: initobj ""T"" - IL_000a: ldloc.s V_5 - IL_000c: box ""T"" + IL_0002: ldtoken ""T"" + IL_0007: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000c: call ""bool System.Type.IsValueType.get"" IL_0011: brtrue.s IL_001e IL_0013: ldloc.2 IL_0014: ldobj ""T"" @@ -19199,86 +19060,82 @@ .locals init (int V_0, verifier.VerifyIL("Program.d__2.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @" { - // Code size 332 (0x14c) + // Code size 333 (0x14d) .maxstack 4 .locals init (int V_0, int V_1, int V_2, - T V_3, - System.Runtime.CompilerServices.TaskAwaiter V_4, - System.Exception V_5) + System.Runtime.CompilerServices.TaskAwaiter V_3, + System.Exception V_4) IL_0000: ldarg.0 IL_0001: ldfld ""int Program.d__2.<>1__state"" IL_0006: stloc.0 .try { IL_0007: ldloc.0 - IL_0008: brfalse.s IL_006a - IL_000a: ldloca.s V_3 - IL_000c: initobj ""T"" - IL_0012: ldloc.3 - IL_0013: box ""T"" - IL_0018: brtrue.s IL_0026 - IL_001a: ldarg.0 + IL_0008: brfalse.s IL_0069 + IL_000a: ldtoken ""T"" + IL_000f: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0014: call ""bool System.Type.IsValueType.get"" + IL_0019: brtrue.s IL_0027 IL_001b: ldarg.0 - IL_001c: ldfld ""T Program.d__2.item"" - IL_0021: stfld ""T Program.d__2.<>7__wrap1"" - IL_0026: ldarg.0 - IL_0027: ldflda ""T Program.d__2.item"" - IL_002c: call ""int Program.GetOffset(ref T)"" - IL_0031: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" - IL_0036: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_003b: stloc.s V_4 - IL_003d: ldloca.s V_4 + IL_001c: ldarg.0 + IL_001d: ldfld ""T Program.d__2.item"" + IL_0022: stfld ""T Program.d__2.<>7__wrap1"" + IL_0027: ldarg.0 + IL_0028: ldflda ""T Program.d__2.item"" + IL_002d: call ""int Program.GetOffset(ref T)"" + IL_0032: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" + IL_0037: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_003c: stloc.3 + IL_003d: ldloca.s V_3 IL_003f: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_0044: brtrue.s IL_0087 + IL_0044: brtrue.s IL_0085 IL_0046: ldarg.0 IL_0047: ldc.i4.0 IL_0048: dup IL_0049: stloc.0 IL_004a: stfld ""int Program.d__2.<>1__state"" IL_004f: ldarg.0 - IL_0050: ldloc.s V_4 - IL_0052: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_0057: ldarg.0 - IL_0058: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_005d: ldloca.s V_4 - IL_005f: ldarg.0 - IL_0060: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" - IL_0065: leave IL_014b - IL_006a: ldarg.0 - IL_006b: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_0070: stloc.s V_4 - IL_0072: ldarg.0 - IL_0073: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_0078: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_007e: ldarg.0 - IL_007f: ldc.i4.m1 - IL_0080: dup - IL_0081: stloc.0 - IL_0082: stfld ""int Program.d__2.<>1__state"" - IL_0087: ldloca.s V_4 - IL_0089: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_008e: stloc.1 - IL_008f: ldloca.s V_3 - IL_0091: initobj ""T"" - IL_0097: ldloc.3 - IL_0098: box ""T"" - IL_009d: brtrue.s IL_00a7 - IL_009f: ldarg.0 - IL_00a0: ldflda ""T Program.d__2.<>7__wrap1"" - IL_00a5: br.s IL_00ad - IL_00a7: ldarg.0 - IL_00a8: ldflda ""T Program.d__2.item"" - IL_00ad: constrained. ""T"" - IL_00b3: callvirt ""int IMoveable.Length.get"" - IL_00b8: ldloc.1 - IL_00b9: sub - IL_00ba: stloc.2 - IL_00bb: ldloca.s V_3 - IL_00bd: initobj ""T"" - IL_00c3: ldloc.3 - IL_00c4: box ""T"" + IL_0050: ldloc.3 + IL_0051: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_0056: ldarg.0 + IL_0057: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_005c: ldloca.s V_3 + IL_005e: ldarg.0 + IL_005f: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" + IL_0064: leave IL_014c + IL_0069: ldarg.0 + IL_006a: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_006f: stloc.3 + IL_0070: ldarg.0 + IL_0071: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_0076: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_007c: ldarg.0 + IL_007d: ldc.i4.m1 + IL_007e: dup + IL_007f: stloc.0 + IL_0080: stfld ""int Program.d__2.<>1__state"" + IL_0085: ldloca.s V_3 + IL_0087: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_008c: stloc.1 + IL_008d: ldtoken ""T"" + IL_0092: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0097: call ""bool System.Type.IsValueType.get"" + IL_009c: brtrue.s IL_00a6 + IL_009e: ldarg.0 + IL_009f: ldflda ""T Program.d__2.<>7__wrap1"" + IL_00a4: br.s IL_00ac + IL_00a6: ldarg.0 + IL_00a7: ldflda ""T Program.d__2.item"" + IL_00ac: constrained. ""T"" + IL_00b2: callvirt ""int IMoveable.Length.get"" + IL_00b7: ldloc.1 + IL_00b8: sub + IL_00b9: stloc.2 + IL_00ba: ldtoken ""T"" + IL_00bf: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_00c4: call ""bool System.Type.IsValueType.get"" IL_00c9: brtrue.s IL_00d3 IL_00cb: ldarg.0 IL_00cc: ldflda ""T Program.d__2.<>7__wrap1"" @@ -19286,47 +19143,46 @@ .locals init (int V_0, IL_00d3: ldarg.0 IL_00d4: ldflda ""T Program.d__2.item"" IL_00d9: ldloc.2 - IL_00da: ldloca.s V_3 - IL_00dc: initobj ""T"" - IL_00e2: ldloc.3 - IL_00e3: box ""T"" - IL_00e8: brtrue.s IL_00f2 - IL_00ea: ldarg.0 - IL_00eb: ldflda ""T Program.d__2.<>7__wrap1"" - IL_00f0: br.s IL_00f8 - IL_00f2: ldarg.0 - IL_00f3: ldflda ""T Program.d__2.item"" - IL_00f8: ldloc.2 - IL_00f9: constrained. ""T"" - IL_00ff: callvirt ""int IMoveable.this[int].get"" - IL_0104: ldc.i4.1 - IL_0105: add - IL_0106: constrained. ""T"" - IL_010c: callvirt ""void IMoveable.this[int].set"" - IL_0111: ldarg.0 - IL_0112: ldflda ""T Program.d__2.<>7__wrap1"" - IL_0117: initobj ""T"" - IL_011d: leave.s IL_0138 + IL_00da: ldtoken ""T"" + IL_00df: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_00e4: call ""bool System.Type.IsValueType.get"" + IL_00e9: brtrue.s IL_00f3 + IL_00eb: ldarg.0 + IL_00ec: ldflda ""T Program.d__2.<>7__wrap1"" + IL_00f1: br.s IL_00f9 + IL_00f3: ldarg.0 + IL_00f4: ldflda ""T Program.d__2.item"" + IL_00f9: ldloc.2 + IL_00fa: constrained. ""T"" + IL_0100: callvirt ""int IMoveable.this[int].get"" + IL_0105: ldc.i4.1 + IL_0106: add + IL_0107: constrained. ""T"" + IL_010d: callvirt ""void IMoveable.this[int].set"" + IL_0112: ldarg.0 + IL_0113: ldflda ""T Program.d__2.<>7__wrap1"" + IL_0118: initobj ""T"" + IL_011e: leave.s IL_0139 } catch System.Exception { - IL_011f: stloc.s V_5 - IL_0121: ldarg.0 - IL_0122: ldc.i4.s -2 - IL_0124: stfld ""int Program.d__2.<>1__state"" - IL_0129: ldarg.0 - IL_012a: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_012f: ldloc.s V_5 - IL_0131: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" - IL_0136: leave.s IL_014b + IL_0120: stloc.s V_4 + IL_0122: ldarg.0 + IL_0123: ldc.i4.s -2 + IL_0125: stfld ""int Program.d__2.<>1__state"" + IL_012a: ldarg.0 + IL_012b: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_0130: ldloc.s V_4 + IL_0132: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" + IL_0137: leave.s IL_014c } - IL_0138: ldarg.0 - IL_0139: ldc.i4.s -2 - IL_013b: stfld ""int Program.d__2.<>1__state"" - IL_0140: ldarg.0 - IL_0141: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_0146: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" - IL_014b: ret + IL_0139: ldarg.0 + IL_013a: ldc.i4.s -2 + IL_013c: stfld ""int Program.d__2.<>1__state"" + IL_0141: ldarg.0 + IL_0142: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_0147: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" + IL_014c: ret } "); } @@ -19627,7 +19483,7 @@ .locals init (T V_0, verifier.VerifyIL("Program.Shift2", @" { - // Code size 77 (0x4d) + // Code size 78 (0x4e) .maxstack 4 .locals init (T& V_0, int V_1, @@ -19641,25 +19497,24 @@ .locals init (T& V_0, IL_0010: sub IL_0011: stloc.1 IL_0012: ldloc.0 - IL_0013: ldloca.s V_2 - IL_0015: initobj ""T"" - IL_001b: ldloc.2 - IL_001c: box ""T"" - IL_0021: brtrue.s IL_002b - IL_0023: ldobj ""T"" - IL_0028: stloc.2 - IL_0029: ldloca.s V_2 - IL_002b: ldloc.1 - IL_002c: ldloc.0 - IL_002d: ldloc.1 - IL_002e: constrained. ""T"" - IL_0034: callvirt ""int IMoveable.this[int].get"" - IL_0039: ldarga.s V_0 - IL_003b: call ""int Program.GetOffset(ref T)"" - IL_0040: add - IL_0041: constrained. ""T"" - IL_0047: callvirt ""void IMoveable.this[int].set"" - IL_004c: ret + IL_0013: ldtoken ""T"" + IL_0018: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_001d: call ""bool System.Type.IsValueType.get"" + IL_0022: brtrue.s IL_002c + IL_0024: ldobj ""T"" + IL_0029: stloc.2 + IL_002a: ldloca.s V_2 + IL_002c: ldloc.1 + IL_002d: ldloc.0 + IL_002e: ldloc.1 + IL_002f: constrained. ""T"" + IL_0035: callvirt ""int IMoveable.this[int].get"" + IL_003a: ldarga.s V_0 + IL_003c: call ""int Program.GetOffset(ref T)"" + IL_0041: add + IL_0042: constrained. ""T"" + IL_0048: callvirt ""void IMoveable.this[int].set"" + IL_004d: ret } "); } @@ -19887,7 +19742,7 @@ .locals init (T V_0, verifier.VerifyIL("Program.Shift2", @" { - // Code size 75 (0x4b) + // Code size 76 (0x4c) .maxstack 4 .locals init (T& V_0, int V_1, @@ -19901,25 +19756,24 @@ .locals init (T& V_0, IL_000f: sub IL_0010: stloc.1 IL_0011: ldloc.0 - IL_0012: ldloca.s V_2 - IL_0014: initobj ""T"" - IL_001a: ldloc.2 - IL_001b: box ""T"" - IL_0020: brtrue.s IL_002a - IL_0022: ldobj ""T"" - IL_0027: stloc.2 - IL_0028: ldloca.s V_2 - IL_002a: ldloc.1 - IL_002b: ldloc.0 - IL_002c: ldloc.1 - IL_002d: constrained. ""T"" - IL_0033: callvirt ""int IMoveable.this[int].get"" - IL_0038: ldarg.0 - IL_0039: call ""int Program.GetOffset(ref T)"" - IL_003e: add - IL_003f: constrained. ""T"" - IL_0045: callvirt ""void IMoveable.this[int].set"" - IL_004a: ret + IL_0012: ldtoken ""T"" + IL_0017: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_001c: call ""bool System.Type.IsValueType.get"" + IL_0021: brtrue.s IL_002b + IL_0023: ldobj ""T"" + IL_0028: stloc.2 + IL_0029: ldloca.s V_2 + IL_002b: ldloc.1 + IL_002c: ldloc.0 + IL_002d: ldloc.1 + IL_002e: constrained. ""T"" + IL_0034: callvirt ""int IMoveable.this[int].get"" + IL_0039: ldarg.0 + IL_003a: call ""int Program.GetOffset(ref T)"" + IL_003f: add + IL_0040: constrained. ""T"" + IL_0046: callvirt ""void IMoveable.this[int].set"" + IL_004b: ret } "); } @@ -20236,21 +20090,20 @@ .locals init (int V_0, verifier.VerifyIL("Program.d__2.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @" { - // Code size 311 (0x137) + // Code size 310 (0x136) .maxstack 4 .locals init (int V_0, int V_1, int V_2, - T V_3, - System.Runtime.CompilerServices.TaskAwaiter V_4, - System.Exception V_5) + System.Runtime.CompilerServices.TaskAwaiter V_3, + System.Exception V_4) IL_0000: ldarg.0 IL_0001: ldfld ""int Program.d__2.<>1__state"" IL_0006: stloc.0 .try { IL_0007: ldloc.0 - IL_0008: brfalse IL_00a0 + IL_0008: brfalse IL_009f IL_000d: ldarg.0 IL_000e: ldflda ""T Program.d__2.item"" IL_0013: constrained. ""T"" @@ -20258,104 +20111,102 @@ .locals init (int V_0, IL_001e: ldc.i4.1 IL_001f: sub IL_0020: stloc.1 - IL_0021: ldloca.s V_3 - IL_0023: initobj ""T"" - IL_0029: ldloc.3 - IL_002a: box ""T"" - IL_002f: brtrue.s IL_003d - IL_0031: ldarg.0 + IL_0021: ldtoken ""T"" + IL_0026: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_002b: call ""bool System.Type.IsValueType.get"" + IL_0030: brtrue.s IL_003e IL_0032: ldarg.0 - IL_0033: ldfld ""T Program.d__2.item"" - IL_0038: stfld ""T Program.d__2.<>7__wrap1"" - IL_003d: ldarg.0 - IL_003e: ldloc.1 - IL_003f: stfld ""int Program.d__2.<>7__wrap2"" - IL_0044: ldarg.0 + IL_0033: ldarg.0 + IL_0034: ldfld ""T Program.d__2.item"" + IL_0039: stfld ""T Program.d__2.<>7__wrap1"" + IL_003e: ldarg.0 + IL_003f: ldloc.1 + IL_0040: stfld ""int Program.d__2.<>7__wrap2"" IL_0045: ldarg.0 - IL_0046: ldflda ""T Program.d__2.item"" - IL_004b: ldloc.1 - IL_004c: constrained. ""T"" - IL_0052: callvirt ""int IMoveable.this[int].get"" - IL_0057: stfld ""int Program.d__2.<>7__wrap3"" - IL_005c: ldarg.0 - IL_005d: ldflda ""T Program.d__2.item"" - IL_0062: call ""int Program.GetOffset(ref T)"" - IL_0067: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" - IL_006c: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_0071: stloc.s V_4 - IL_0073: ldloca.s V_4 + IL_0046: ldarg.0 + IL_0047: ldflda ""T Program.d__2.item"" + IL_004c: ldloc.1 + IL_004d: constrained. ""T"" + IL_0053: callvirt ""int IMoveable.this[int].get"" + IL_0058: stfld ""int Program.d__2.<>7__wrap3"" + IL_005d: ldarg.0 + IL_005e: ldflda ""T Program.d__2.item"" + IL_0063: call ""int Program.GetOffset(ref T)"" + IL_0068: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" + IL_006d: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_0072: stloc.3 + IL_0073: ldloca.s V_3 IL_0075: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_007a: brtrue.s IL_00bd + IL_007a: brtrue.s IL_00bb IL_007c: ldarg.0 IL_007d: ldc.i4.0 IL_007e: dup IL_007f: stloc.0 IL_0080: stfld ""int Program.d__2.<>1__state"" IL_0085: ldarg.0 - IL_0086: ldloc.s V_4 - IL_0088: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_008d: ldarg.0 - IL_008e: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_0093: ldloca.s V_4 - IL_0095: ldarg.0 - IL_0096: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" - IL_009b: leave IL_0136 - IL_00a0: ldarg.0 - IL_00a1: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_00a6: stloc.s V_4 - IL_00a8: ldarg.0 - IL_00a9: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_00ae: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_00b4: ldarg.0 - IL_00b5: ldc.i4.m1 - IL_00b6: dup - IL_00b7: stloc.0 - IL_00b8: stfld ""int Program.d__2.<>1__state"" - IL_00bd: ldloca.s V_4 - IL_00bf: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_00c4: stloc.2 - IL_00c5: ldloca.s V_3 - IL_00c7: initobj ""T"" - IL_00cd: ldloc.3 - IL_00ce: box ""T"" - IL_00d3: brtrue.s IL_00dd - IL_00d5: ldarg.0 - IL_00d6: ldflda ""T Program.d__2.<>7__wrap1"" - IL_00db: br.s IL_00e3 - IL_00dd: ldarg.0 - IL_00de: ldflda ""T Program.d__2.item"" - IL_00e3: ldarg.0 - IL_00e4: ldfld ""int Program.d__2.<>7__wrap2"" - IL_00e9: ldarg.0 - IL_00ea: ldfld ""int Program.d__2.<>7__wrap3"" - IL_00ef: ldloc.2 - IL_00f0: add - IL_00f1: constrained. ""T"" - IL_00f7: callvirt ""void IMoveable.this[int].set"" - IL_00fc: ldarg.0 - IL_00fd: ldflda ""T Program.d__2.<>7__wrap1"" - IL_0102: initobj ""T"" - IL_0108: leave.s IL_0123 + IL_0086: ldloc.3 + IL_0087: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_008c: ldarg.0 + IL_008d: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_0092: ldloca.s V_3 + IL_0094: ldarg.0 + IL_0095: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" + IL_009a: leave IL_0135 + IL_009f: ldarg.0 + IL_00a0: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_00a5: stloc.3 + IL_00a6: ldarg.0 + IL_00a7: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_00ac: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_00b2: ldarg.0 + IL_00b3: ldc.i4.m1 + IL_00b4: dup + IL_00b5: stloc.0 + IL_00b6: stfld ""int Program.d__2.<>1__state"" + IL_00bb: ldloca.s V_3 + IL_00bd: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_00c2: stloc.2 + IL_00c3: ldtoken ""T"" + IL_00c8: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_00cd: call ""bool System.Type.IsValueType.get"" + IL_00d2: brtrue.s IL_00dc + IL_00d4: ldarg.0 + IL_00d5: ldflda ""T Program.d__2.<>7__wrap1"" + IL_00da: br.s IL_00e2 + IL_00dc: ldarg.0 + IL_00dd: ldflda ""T Program.d__2.item"" + IL_00e2: ldarg.0 + IL_00e3: ldfld ""int Program.d__2.<>7__wrap2"" + IL_00e8: ldarg.0 + IL_00e9: ldfld ""int Program.d__2.<>7__wrap3"" + IL_00ee: ldloc.2 + IL_00ef: add + IL_00f0: constrained. ""T"" + IL_00f6: callvirt ""void IMoveable.this[int].set"" + IL_00fb: ldarg.0 + IL_00fc: ldflda ""T Program.d__2.<>7__wrap1"" + IL_0101: initobj ""T"" + IL_0107: leave.s IL_0122 } catch System.Exception { - IL_010a: stloc.s V_5 - IL_010c: ldarg.0 - IL_010d: ldc.i4.s -2 - IL_010f: stfld ""int Program.d__2.<>1__state"" - IL_0114: ldarg.0 - IL_0115: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_011a: ldloc.s V_5 - IL_011c: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" - IL_0121: leave.s IL_0136 + IL_0109: stloc.s V_4 + IL_010b: ldarg.0 + IL_010c: ldc.i4.s -2 + IL_010e: stfld ""int Program.d__2.<>1__state"" + IL_0113: ldarg.0 + IL_0114: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_0119: ldloc.s V_4 + IL_011b: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" + IL_0120: leave.s IL_0135 } - IL_0123: ldarg.0 - IL_0124: ldc.i4.s -2 - IL_0126: stfld ""int Program.d__2.<>1__state"" - IL_012b: ldarg.0 - IL_012c: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_0131: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" - IL_0136: ret + IL_0122: ldarg.0 + IL_0123: ldc.i4.s -2 + IL_0125: stfld ""int Program.d__2.<>1__state"" + IL_012a: ldarg.0 + IL_012b: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_0130: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" + IL_0135: ret } "); } @@ -20674,14 +20525,12 @@ .locals init (T& V_0, T V_1, T& V_2, int V_3, - int V_4, - T V_5) + int V_4) IL_0000: ldarga.s V_0 IL_0002: stloc.2 - IL_0003: ldloca.s V_5 - IL_0005: initobj ""T"" - IL_000b: ldloc.s V_5 - IL_000d: box ""T"" + IL_0003: ldtoken ""T"" + IL_0008: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000d: call ""bool System.Type.IsValueType.get"" IL_0012: brtrue.s IL_001f IL_0014: ldloc.2 IL_0015: ldobj ""T"" @@ -20952,14 +20801,12 @@ .locals init (T& V_0, T V_1, T& V_2, int V_3, - int V_4, - T V_5) + int V_4) IL_0000: ldarg.0 IL_0001: stloc.2 - IL_0002: ldloca.s V_5 - IL_0004: initobj ""T"" - IL_000a: ldloc.s V_5 - IL_000c: box ""T"" + IL_0002: ldtoken ""T"" + IL_0007: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000c: call ""bool System.Type.IsValueType.get"" IL_0011: brtrue.s IL_001e IL_0013: ldloc.2 IL_0014: ldobj ""T"" @@ -21320,9 +21167,8 @@ .locals init (int V_0, int V_1, int V_2, int V_3, - T V_4, - System.Runtime.CompilerServices.TaskAwaiter V_5, - System.Exception V_6) + System.Runtime.CompilerServices.TaskAwaiter V_4, + System.Exception V_5) IL_0000: ldarg.0 IL_0001: ldfld ""int Program.d__2.<>1__state"" IL_0006: stloc.0 @@ -21330,10 +21176,9 @@ .locals init (int V_0, { IL_0007: ldloc.0 IL_0008: brfalse IL_00df - IL_000d: ldloca.s V_4 - IL_000f: initobj ""T"" - IL_0015: ldloc.s V_4 - IL_0017: box ""T"" + IL_000d: ldtoken ""T"" + IL_0012: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0017: call ""bool System.Type.IsValueType.get"" IL_001c: brtrue.s IL_002a IL_001e: ldarg.0 IL_001f: ldarg.0 @@ -21343,10 +21188,9 @@ .locals init (int V_0, IL_002b: ldflda ""T Program.d__2.item"" IL_0030: call ""int Program.GetOffset(ref T)"" IL_0035: stloc.1 - IL_0036: ldloca.s V_4 - IL_0038: initobj ""T"" - IL_003e: ldloc.s V_4 - IL_0040: box ""T"" + IL_0036: ldtoken ""T"" + IL_003b: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0040: call ""bool System.Type.IsValueType.get"" IL_0045: brtrue.s IL_004f IL_0047: ldarg.0 IL_0048: ldflda ""T Program.d__2.<>7__wrap1"" @@ -21362,10 +21206,9 @@ .locals init (int V_0, IL_0064: ldloc.2 IL_0065: stfld ""int Program.d__2.<>7__wrap2"" IL_006a: ldarg.0 - IL_006b: ldloca.s V_4 - IL_006d: initobj ""T"" - IL_0073: ldloc.s V_4 - IL_0075: box ""T"" + IL_006b: ldtoken ""T"" + IL_0070: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0075: call ""bool System.Type.IsValueType.get"" IL_007a: brtrue.s IL_0084 IL_007c: ldarg.0 IL_007d: ldflda ""T Program.d__2.<>7__wrap1"" @@ -21381,8 +21224,8 @@ .locals init (int V_0, IL_00a1: call ""int Program.GetOffset(ref T)"" IL_00a6: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" IL_00ab: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_00b0: stloc.s V_5 - IL_00b2: ldloca.s V_5 + IL_00b0: stloc.s V_4 + IL_00b2: ldloca.s V_4 IL_00b4: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" IL_00b9: brtrue.s IL_00fc IL_00bb: ldarg.0 @@ -21391,17 +21234,17 @@ .locals init (int V_0, IL_00be: stloc.0 IL_00bf: stfld ""int Program.d__2.<>1__state"" IL_00c4: ldarg.0 - IL_00c5: ldloc.s V_5 + IL_00c5: ldloc.s V_4 IL_00c7: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" IL_00cc: ldarg.0 IL_00cd: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_00d2: ldloca.s V_5 + IL_00d2: ldloca.s V_4 IL_00d4: ldarg.0 IL_00d5: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" IL_00da: leave IL_0176 IL_00df: ldarg.0 IL_00e0: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_00e5: stloc.s V_5 + IL_00e5: stloc.s V_4 IL_00e7: ldarg.0 IL_00e8: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" IL_00ed: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" @@ -21410,13 +21253,12 @@ .locals init (int V_0, IL_00f5: dup IL_00f6: stloc.0 IL_00f7: stfld ""int Program.d__2.<>1__state"" - IL_00fc: ldloca.s V_5 + IL_00fc: ldloca.s V_4 IL_00fe: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" IL_0103: stloc.3 - IL_0104: ldloca.s V_4 - IL_0106: initobj ""T"" - IL_010c: ldloc.s V_4 - IL_010e: box ""T"" + IL_0104: ldtoken ""T"" + IL_0109: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_010e: call ""bool System.Type.IsValueType.get"" IL_0113: brtrue.s IL_011d IL_0115: ldarg.0 IL_0116: ldflda ""T Program.d__2.<>7__wrap1"" @@ -21438,13 +21280,13 @@ .locals init (int V_0, } catch System.Exception { - IL_014a: stloc.s V_6 + IL_014a: stloc.s V_5 IL_014c: ldarg.0 IL_014d: ldc.i4.s -2 IL_014f: stfld ""int Program.d__2.<>1__state"" IL_0154: ldarg.0 IL_0155: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_015a: ldloc.s V_6 + IL_015a: ldloc.s V_5 IL_015c: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" IL_0161: leave.s IL_0176 } @@ -21851,86 +21693,82 @@ .locals init (int V_0, verifier.VerifyIL("Program.d__2.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @" { - // Code size 342 (0x156) + // Code size 343 (0x157) .maxstack 4 .locals init (int V_0, int V_1, int V_2, - T V_3, - System.Runtime.CompilerServices.TaskAwaiter V_4, - System.Exception V_5) + System.Runtime.CompilerServices.TaskAwaiter V_3, + System.Exception V_4) IL_0000: ldarg.0 IL_0001: ldfld ""int Program.d__2.<>1__state"" IL_0006: stloc.0 .try { IL_0007: ldloc.0 - IL_0008: brfalse.s IL_006a - IL_000a: ldloca.s V_3 - IL_000c: initobj ""T"" - IL_0012: ldloc.3 - IL_0013: box ""T"" - IL_0018: brtrue.s IL_0026 - IL_001a: ldarg.0 + IL_0008: brfalse.s IL_0069 + IL_000a: ldtoken ""T"" + IL_000f: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0014: call ""bool System.Type.IsValueType.get"" + IL_0019: brtrue.s IL_0027 IL_001b: ldarg.0 - IL_001c: ldfld ""T Program.d__2.item"" - IL_0021: stfld ""T Program.d__2.<>7__wrap1"" - IL_0026: ldarg.0 - IL_0027: ldflda ""T Program.d__2.item"" - IL_002c: call ""int Program.GetOffset(ref T)"" - IL_0031: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" - IL_0036: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_003b: stloc.s V_4 - IL_003d: ldloca.s V_4 + IL_001c: ldarg.0 + IL_001d: ldfld ""T Program.d__2.item"" + IL_0022: stfld ""T Program.d__2.<>7__wrap1"" + IL_0027: ldarg.0 + IL_0028: ldflda ""T Program.d__2.item"" + IL_002d: call ""int Program.GetOffset(ref T)"" + IL_0032: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" + IL_0037: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_003c: stloc.3 + IL_003d: ldloca.s V_3 IL_003f: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_0044: brtrue.s IL_0087 + IL_0044: brtrue.s IL_0085 IL_0046: ldarg.0 IL_0047: ldc.i4.0 IL_0048: dup IL_0049: stloc.0 IL_004a: stfld ""int Program.d__2.<>1__state"" IL_004f: ldarg.0 - IL_0050: ldloc.s V_4 - IL_0052: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_0057: ldarg.0 - IL_0058: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_005d: ldloca.s V_4 - IL_005f: ldarg.0 - IL_0060: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" - IL_0065: leave IL_0155 - IL_006a: ldarg.0 - IL_006b: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_0070: stloc.s V_4 - IL_0072: ldarg.0 - IL_0073: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_0078: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_007e: ldarg.0 - IL_007f: ldc.i4.m1 - IL_0080: dup - IL_0081: stloc.0 - IL_0082: stfld ""int Program.d__2.<>1__state"" - IL_0087: ldloca.s V_4 - IL_0089: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_008e: stloc.1 - IL_008f: ldloca.s V_3 - IL_0091: initobj ""T"" - IL_0097: ldloc.3 - IL_0098: box ""T"" - IL_009d: brtrue.s IL_00a7 - IL_009f: ldarg.0 - IL_00a0: ldflda ""T Program.d__2.<>7__wrap1"" - IL_00a5: br.s IL_00ad - IL_00a7: ldarg.0 - IL_00a8: ldflda ""T Program.d__2.item"" - IL_00ad: constrained. ""T"" - IL_00b3: callvirt ""int IMoveable.Length.get"" - IL_00b8: ldloc.1 - IL_00b9: sub - IL_00ba: stloc.2 - IL_00bb: ldloca.s V_3 - IL_00bd: initobj ""T"" - IL_00c3: ldloc.3 - IL_00c4: box ""T"" + IL_0050: ldloc.3 + IL_0051: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_0056: ldarg.0 + IL_0057: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_005c: ldloca.s V_3 + IL_005e: ldarg.0 + IL_005f: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" + IL_0064: leave IL_0156 + IL_0069: ldarg.0 + IL_006a: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_006f: stloc.3 + IL_0070: ldarg.0 + IL_0071: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_0076: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_007c: ldarg.0 + IL_007d: ldc.i4.m1 + IL_007e: dup + IL_007f: stloc.0 + IL_0080: stfld ""int Program.d__2.<>1__state"" + IL_0085: ldloca.s V_3 + IL_0087: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_008c: stloc.1 + IL_008d: ldtoken ""T"" + IL_0092: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0097: call ""bool System.Type.IsValueType.get"" + IL_009c: brtrue.s IL_00a6 + IL_009e: ldarg.0 + IL_009f: ldflda ""T Program.d__2.<>7__wrap1"" + IL_00a4: br.s IL_00ac + IL_00a6: ldarg.0 + IL_00a7: ldflda ""T Program.d__2.item"" + IL_00ac: constrained. ""T"" + IL_00b2: callvirt ""int IMoveable.Length.get"" + IL_00b7: ldloc.1 + IL_00b8: sub + IL_00b9: stloc.2 + IL_00ba: ldtoken ""T"" + IL_00bf: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_00c4: call ""bool System.Type.IsValueType.get"" IL_00c9: brtrue.s IL_00d3 IL_00cb: ldarg.0 IL_00cc: ldflda ""T Program.d__2.<>7__wrap1"" @@ -21938,49 +21776,48 @@ .locals init (int V_0, IL_00d3: ldarg.0 IL_00d4: ldflda ""T Program.d__2.item"" IL_00d9: ldloc.2 - IL_00da: ldloca.s V_3 - IL_00dc: initobj ""T"" - IL_00e2: ldloc.3 - IL_00e3: box ""T"" - IL_00e8: brtrue.s IL_00f2 - IL_00ea: ldarg.0 - IL_00eb: ldflda ""T Program.d__2.<>7__wrap1"" - IL_00f0: br.s IL_00f8 - IL_00f2: ldarg.0 - IL_00f3: ldflda ""T Program.d__2.item"" - IL_00f8: ldloc.2 - IL_00f9: constrained. ""T"" - IL_00ff: callvirt ""int IMoveable.this[int].get"" - IL_0104: ldarg.0 - IL_0105: ldflda ""T Program.d__2.item"" - IL_010a: call ""int Program.GetOffset(ref T)"" - IL_010f: add - IL_0110: constrained. ""T"" - IL_0116: callvirt ""void IMoveable.this[int].set"" - IL_011b: ldarg.0 - IL_011c: ldflda ""T Program.d__2.<>7__wrap1"" - IL_0121: initobj ""T"" - IL_0127: leave.s IL_0142 + IL_00da: ldtoken ""T"" + IL_00df: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_00e4: call ""bool System.Type.IsValueType.get"" + IL_00e9: brtrue.s IL_00f3 + IL_00eb: ldarg.0 + IL_00ec: ldflda ""T Program.d__2.<>7__wrap1"" + IL_00f1: br.s IL_00f9 + IL_00f3: ldarg.0 + IL_00f4: ldflda ""T Program.d__2.item"" + IL_00f9: ldloc.2 + IL_00fa: constrained. ""T"" + IL_0100: callvirt ""int IMoveable.this[int].get"" + IL_0105: ldarg.0 + IL_0106: ldflda ""T Program.d__2.item"" + IL_010b: call ""int Program.GetOffset(ref T)"" + IL_0110: add + IL_0111: constrained. ""T"" + IL_0117: callvirt ""void IMoveable.this[int].set"" + IL_011c: ldarg.0 + IL_011d: ldflda ""T Program.d__2.<>7__wrap1"" + IL_0122: initobj ""T"" + IL_0128: leave.s IL_0143 } catch System.Exception { - IL_0129: stloc.s V_5 - IL_012b: ldarg.0 - IL_012c: ldc.i4.s -2 - IL_012e: stfld ""int Program.d__2.<>1__state"" - IL_0133: ldarg.0 - IL_0134: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_0139: ldloc.s V_5 - IL_013b: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" - IL_0140: leave.s IL_0155 + IL_012a: stloc.s V_4 + IL_012c: ldarg.0 + IL_012d: ldc.i4.s -2 + IL_012f: stfld ""int Program.d__2.<>1__state"" + IL_0134: ldarg.0 + IL_0135: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_013a: ldloc.s V_4 + IL_013c: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" + IL_0141: leave.s IL_0156 } - IL_0142: ldarg.0 - IL_0143: ldc.i4.s -2 - IL_0145: stfld ""int Program.d__2.<>1__state"" - IL_014a: ldarg.0 - IL_014b: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_0150: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" - IL_0155: ret + IL_0143: ldarg.0 + IL_0144: ldc.i4.s -2 + IL_0146: stfld ""int Program.d__2.<>1__state"" + IL_014b: ldarg.0 + IL_014c: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_0151: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" + IL_0156: ret } "); } @@ -22426,9 +22263,8 @@ .locals init (int V_0, int V_1, int V_2, int V_3, - T V_4, - System.Runtime.CompilerServices.TaskAwaiter V_5, - System.Exception V_6) + System.Runtime.CompilerServices.TaskAwaiter V_4, + System.Exception V_5) IL_0000: ldarg.0 IL_0001: ldfld ""int Program.d__2.<>1__state"" IL_0006: stloc.0 @@ -22439,10 +22275,9 @@ .locals init (int V_0, IL_000a: ldloc.0 IL_000b: ldc.i4.1 IL_000c: beq IL_0140 - IL_0011: ldloca.s V_4 - IL_0013: initobj ""T"" - IL_0019: ldloc.s V_4 - IL_001b: box ""T"" + IL_0011: ldtoken ""T"" + IL_0016: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_001b: call ""bool System.Type.IsValueType.get"" IL_0020: brtrue.s IL_002e IL_0022: ldarg.0 IL_0023: ldarg.0 @@ -22453,8 +22288,8 @@ .locals init (int V_0, IL_0034: call ""int Program.GetOffset(ref T)"" IL_0039: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" IL_003e: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_0043: stloc.s V_5 - IL_0045: ldloca.s V_5 + IL_0043: stloc.s V_4 + IL_0045: ldloca.s V_4 IL_0047: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" IL_004c: brtrue.s IL_008f IL_004e: ldarg.0 @@ -22463,17 +22298,17 @@ .locals init (int V_0, IL_0051: stloc.0 IL_0052: stfld ""int Program.d__2.<>1__state"" IL_0057: ldarg.0 - IL_0058: ldloc.s V_5 + IL_0058: ldloc.s V_4 IL_005a: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" IL_005f: ldarg.0 IL_0060: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_0065: ldloca.s V_5 + IL_0065: ldloca.s V_4 IL_0067: ldarg.0 IL_0068: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" IL_006d: leave IL_01d7 IL_0072: ldarg.0 IL_0073: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_0078: stloc.s V_5 + IL_0078: stloc.s V_4 IL_007a: ldarg.0 IL_007b: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" IL_0080: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" @@ -22482,13 +22317,12 @@ .locals init (int V_0, IL_0088: dup IL_0089: stloc.0 IL_008a: stfld ""int Program.d__2.<>1__state"" - IL_008f: ldloca.s V_5 + IL_008f: ldloca.s V_4 IL_0091: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" IL_0096: stloc.1 - IL_0097: ldloca.s V_4 - IL_0099: initobj ""T"" - IL_009f: ldloc.s V_4 - IL_00a1: box ""T"" + IL_0097: ldtoken ""T"" + IL_009c: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_00a1: call ""bool System.Type.IsValueType.get"" IL_00a6: brtrue.s IL_00b0 IL_00a8: ldarg.0 IL_00a9: ldflda ""T Program.d__2.<>7__wrap1"" @@ -22504,10 +22338,9 @@ .locals init (int V_0, IL_00c5: ldloc.2 IL_00c6: stfld ""int Program.d__2.<>7__wrap2"" IL_00cb: ldarg.0 - IL_00cc: ldloca.s V_4 - IL_00ce: initobj ""T"" - IL_00d4: ldloc.s V_4 - IL_00d6: box ""T"" + IL_00cc: ldtoken ""T"" + IL_00d1: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_00d6: call ""bool System.Type.IsValueType.get"" IL_00db: brtrue.s IL_00e5 IL_00dd: ldarg.0 IL_00de: ldflda ""T Program.d__2.<>7__wrap1"" @@ -22523,8 +22356,8 @@ .locals init (int V_0, IL_0102: call ""int Program.GetOffset(ref T)"" IL_0107: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" IL_010c: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_0111: stloc.s V_5 - IL_0113: ldloca.s V_5 + IL_0111: stloc.s V_4 + IL_0113: ldloca.s V_4 IL_0115: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" IL_011a: brtrue.s IL_015d IL_011c: ldarg.0 @@ -22533,17 +22366,17 @@ .locals init (int V_0, IL_011f: stloc.0 IL_0120: stfld ""int Program.d__2.<>1__state"" IL_0125: ldarg.0 - IL_0126: ldloc.s V_5 + IL_0126: ldloc.s V_4 IL_0128: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" IL_012d: ldarg.0 IL_012e: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_0133: ldloca.s V_5 + IL_0133: ldloca.s V_4 IL_0135: ldarg.0 IL_0136: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" IL_013b: leave IL_01d7 IL_0140: ldarg.0 IL_0141: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_0146: stloc.s V_5 + IL_0146: stloc.s V_4 IL_0148: ldarg.0 IL_0149: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" IL_014e: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" @@ -22552,13 +22385,12 @@ .locals init (int V_0, IL_0156: dup IL_0157: stloc.0 IL_0158: stfld ""int Program.d__2.<>1__state"" - IL_015d: ldloca.s V_5 + IL_015d: ldloca.s V_4 IL_015f: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" IL_0164: stloc.3 - IL_0165: ldloca.s V_4 - IL_0167: initobj ""T"" - IL_016d: ldloc.s V_4 - IL_016f: box ""T"" + IL_0165: ldtoken ""T"" + IL_016a: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_016f: call ""bool System.Type.IsValueType.get"" IL_0174: brtrue.s IL_017e IL_0176: ldarg.0 IL_0177: ldflda ""T Program.d__2.<>7__wrap1"" @@ -22580,13 +22412,13 @@ .locals init (int V_0, } catch System.Exception { - IL_01ab: stloc.s V_6 + IL_01ab: stloc.s V_5 IL_01ad: ldarg.0 IL_01ae: ldc.i4.s -2 IL_01b0: stfld ""int Program.d__2.<>1__state"" IL_01b5: ldarg.0 IL_01b6: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_01bb: ldloc.s V_6 + IL_01bb: ldloc.s V_5 IL_01bd: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" IL_01c2: leave.s IL_01d7 } @@ -22972,14 +22804,12 @@ .locals init (T& V_0, int V_4, int? V_5, int V_6, - T V_7, - int? V_8) + int? V_7) IL_0000: ldarga.s V_0 IL_0002: stloc.2 - IL_0003: ldloca.s V_7 - IL_0005: initobj ""T"" - IL_000b: ldloc.s V_7 - IL_000d: box ""T"" + IL_0003: ldtoken ""T"" + IL_0008: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000d: call ""bool System.Type.IsValueType.get"" IL_0012: brtrue.s IL_001f IL_0014: ldloc.2 IL_0015: ldobj ""T"" @@ -23012,10 +22842,10 @@ .locals init (T& V_0, IL_005c: stloc.s V_6 IL_005e: ldloc.0 IL_005f: ldloc.s V_4 - IL_0061: ldloca.s V_8 + IL_0061: ldloca.s V_7 IL_0063: ldloc.s V_6 IL_0065: call ""int?..ctor(int)"" - IL_006a: ldloc.s V_8 + IL_006a: ldloc.s V_7 IL_006c: constrained. ""T"" IL_0072: callvirt ""void IMoveable.this[int].set"" IL_0077: ret @@ -23289,14 +23119,12 @@ .locals init (T& V_0, int V_4, int? V_5, int V_6, - T V_7, - int? V_8) + int? V_7) IL_0000: ldarg.0 IL_0001: stloc.2 - IL_0002: ldloca.s V_7 - IL_0004: initobj ""T"" - IL_000a: ldloc.s V_7 - IL_000c: box ""T"" + IL_0002: ldtoken ""T"" + IL_0007: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000c: call ""bool System.Type.IsValueType.get"" IL_0011: brtrue.s IL_001e IL_0013: ldloc.2 IL_0014: ldobj ""T"" @@ -23329,10 +23157,10 @@ .locals init (T& V_0, IL_005a: stloc.s V_6 IL_005c: ldloc.0 IL_005d: ldloc.s V_4 - IL_005f: ldloca.s V_8 + IL_005f: ldloca.s V_7 IL_0061: ldloc.s V_6 IL_0063: call ""int?..ctor(int)"" - IL_0068: ldloc.s V_8 + IL_0068: ldloc.s V_7 IL_006a: constrained. ""T"" IL_0070: callvirt ""void IMoveable.this[int].set"" IL_0075: ret @@ -23681,10 +23509,9 @@ .locals init (int V_0, int V_2, int? V_3, int V_4, - T V_5, - System.Runtime.CompilerServices.TaskAwaiter V_6, - int? V_7, - System.Exception V_8) + System.Runtime.CompilerServices.TaskAwaiter V_5, + int? V_6, + System.Exception V_7) IL_0000: ldarg.0 IL_0001: ldfld ""int Program.d__2.<>1__state"" IL_0006: stloc.0 @@ -23692,10 +23519,9 @@ .locals init (int V_0, { IL_0007: ldloc.0 IL_0008: brfalse.s IL_006b - IL_000a: ldloca.s V_5 - IL_000c: initobj ""T"" - IL_0012: ldloc.s V_5 - IL_0014: box ""T"" + IL_000a: ldtoken ""T"" + IL_000f: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0014: call ""bool System.Type.IsValueType.get"" IL_0019: brtrue.s IL_0027 IL_001b: ldarg.0 IL_001c: ldarg.0 @@ -23706,8 +23532,8 @@ .locals init (int V_0, IL_002d: call ""int Program.GetOffset(ref T)"" IL_0032: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" IL_0037: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_003c: stloc.s V_6 - IL_003e: ldloca.s V_6 + IL_003c: stloc.s V_5 + IL_003e: ldloca.s V_5 IL_0040: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" IL_0045: brtrue.s IL_0088 IL_0047: ldarg.0 @@ -23716,17 +23542,17 @@ .locals init (int V_0, IL_004a: stloc.0 IL_004b: stfld ""int Program.d__2.<>1__state"" IL_0050: ldarg.0 - IL_0051: ldloc.s V_6 + IL_0051: ldloc.s V_5 IL_0053: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" IL_0058: ldarg.0 IL_0059: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_005e: ldloca.s V_6 + IL_005e: ldloca.s V_5 IL_0060: ldarg.0 IL_0061: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" IL_0066: leave IL_016d IL_006b: ldarg.0 IL_006c: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_0071: stloc.s V_6 + IL_0071: stloc.s V_5 IL_0073: ldarg.0 IL_0074: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" IL_0079: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" @@ -23735,13 +23561,12 @@ .locals init (int V_0, IL_0081: dup IL_0082: stloc.0 IL_0083: stfld ""int Program.d__2.<>1__state"" - IL_0088: ldloca.s V_6 + IL_0088: ldloca.s V_5 IL_008a: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" IL_008f: stloc.1 - IL_0090: ldloca.s V_5 - IL_0092: initobj ""T"" - IL_0098: ldloc.s V_5 - IL_009a: box ""T"" + IL_0090: ldtoken ""T"" + IL_0095: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_009a: call ""bool System.Type.IsValueType.get"" IL_009f: brtrue.s IL_00a9 IL_00a1: ldarg.0 IL_00a2: ldflda ""T Program.d__2.<>7__wrap1"" @@ -23753,10 +23578,9 @@ .locals init (int V_0, IL_00ba: ldloc.1 IL_00bb: sub IL_00bc: stloc.2 - IL_00bd: ldloca.s V_5 - IL_00bf: initobj ""T"" - IL_00c5: ldloc.s V_5 - IL_00c7: box ""T"" + IL_00bd: ldtoken ""T"" + IL_00c2: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_00c7: call ""bool System.Type.IsValueType.get"" IL_00cc: brtrue.s IL_00d6 IL_00ce: ldarg.0 IL_00cf: ldflda ""T Program.d__2.<>7__wrap1"" @@ -23775,10 +23599,9 @@ .locals init (int V_0, IL_00f9: brtrue.s IL_0133 IL_00fb: ldc.i4.1 IL_00fc: stloc.s V_4 - IL_00fe: ldloca.s V_5 - IL_0100: initobj ""T"" - IL_0106: ldloc.s V_5 - IL_0108: box ""T"" + IL_00fe: ldtoken ""T"" + IL_0103: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0108: call ""bool System.Type.IsValueType.get"" IL_010d: brtrue.s IL_0117 IL_010f: ldarg.0 IL_0110: ldflda ""T Program.d__2.<>7__wrap1"" @@ -23789,7 +23612,7 @@ .locals init (int V_0, IL_011e: ldloc.s V_4 IL_0120: newobj ""int?..ctor(int)"" IL_0125: dup - IL_0126: stloc.s V_7 + IL_0126: stloc.s V_6 IL_0128: constrained. ""T"" IL_012e: callvirt ""void IMoveable.this[int].set"" IL_0133: ldarg.0 @@ -23799,13 +23622,13 @@ .locals init (int V_0, } catch System.Exception { - IL_0141: stloc.s V_8 + IL_0141: stloc.s V_7 IL_0143: ldarg.0 IL_0144: ldc.i4.s -2 IL_0146: stfld ""int Program.d__2.<>1__state"" IL_014b: ldarg.0 IL_014c: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_0151: ldloc.s V_8 + IL_0151: ldloc.s V_7 IL_0153: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" IL_0158: leave.s IL_016d } @@ -24152,14 +23975,12 @@ .locals init (T& V_0, int V_3, int? V_4, int V_5, - T V_6, - int? V_7) + int? V_6) IL_0000: ldarga.s V_0 IL_0002: stloc.2 - IL_0003: ldloca.s V_6 - IL_0005: initobj ""T"" - IL_000b: ldloc.s V_6 - IL_000d: box ""T"" + IL_0003: ldtoken ""T"" + IL_0008: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000d: call ""bool System.Type.IsValueType.get"" IL_0012: brtrue.s IL_001f IL_0014: ldloc.2 IL_0015: ldobj ""T"" @@ -24190,10 +24011,10 @@ .locals init (T& V_0, IL_0058: stloc.s V_5 IL_005a: ldloc.0 IL_005b: ldloc.3 - IL_005c: ldloca.s V_7 + IL_005c: ldloca.s V_6 IL_005e: ldloc.s V_5 IL_0060: call ""int?..ctor(int)"" - IL_0065: ldloc.s V_7 + IL_0065: ldloc.s V_6 IL_0067: constrained. ""T"" IL_006d: callvirt ""void IMoveable.this[int].set"" IL_0072: ret @@ -24460,14 +24281,12 @@ .locals init (T& V_0, int V_3, int? V_4, int V_5, - T V_6, - int? V_7) + int? V_6) IL_0000: ldarg.0 IL_0001: stloc.2 - IL_0002: ldloca.s V_6 - IL_0004: initobj ""T"" - IL_000a: ldloc.s V_6 - IL_000c: box ""T"" + IL_0002: ldtoken ""T"" + IL_0007: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000c: call ""bool System.Type.IsValueType.get"" IL_0011: brtrue.s IL_001e IL_0013: ldloc.2 IL_0014: ldobj ""T"" @@ -24498,10 +24317,10 @@ .locals init (T& V_0, IL_0056: stloc.s V_5 IL_0058: ldloc.0 IL_0059: ldloc.3 - IL_005a: ldloca.s V_7 + IL_005a: ldloca.s V_6 IL_005c: ldloc.s V_5 IL_005e: call ""int?..ctor(int)"" - IL_0063: ldloc.s V_7 + IL_0063: ldloc.s V_6 IL_0065: constrained. ""T"" IL_006b: callvirt ""void IMoveable.this[int].set"" IL_0070: ret @@ -24839,94 +24658,90 @@ .locals init (int V_0, verifier.VerifyIL("Program.d__2.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @" { - // Code size 378 (0x17a) + // Code size 379 (0x17b) .maxstack 4 .locals init (int V_0, int? V_1, int V_2, - T V_3, - System.Runtime.CompilerServices.TaskAwaiter V_4, - int? V_5, - System.Exception V_6) + System.Runtime.CompilerServices.TaskAwaiter V_3, + int? V_4, + System.Exception V_5) IL_0000: ldarg.0 IL_0001: ldfld ""int Program.d__2.<>1__state"" IL_0006: stloc.0 .try { IL_0007: ldloc.0 - IL_0008: brfalse IL_00e2 - IL_000d: ldloca.s V_3 - IL_000f: initobj ""T"" - IL_0015: ldloc.3 - IL_0016: box ""T"" - IL_001b: brtrue.s IL_0029 - IL_001d: ldarg.0 + IL_0008: brfalse IL_00e3 + IL_000d: ldtoken ""T"" + IL_0012: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0017: call ""bool System.Type.IsValueType.get"" + IL_001c: brtrue.s IL_002a IL_001e: ldarg.0 - IL_001f: ldfld ""T Program.d__2.item"" - IL_0024: stfld ""T Program.d__2.<>7__wrap1"" - IL_0029: ldarg.0 - IL_002a: ldloca.s V_3 - IL_002c: initobj ""T"" - IL_0032: ldloc.3 - IL_0033: box ""T"" - IL_0038: brtrue.s IL_0042 - IL_003a: ldarg.0 - IL_003b: ldflda ""T Program.d__2.<>7__wrap1"" - IL_0040: br.s IL_0048 - IL_0042: ldarg.0 - IL_0043: ldflda ""T Program.d__2.item"" - IL_0048: constrained. ""T"" - IL_004e: callvirt ""int IMoveable.Length.get"" - IL_0053: ldc.i4.1 - IL_0054: sub - IL_0055: stfld ""int Program.d__2.<>7__wrap2"" - IL_005a: ldloca.s V_3 - IL_005c: initobj ""T"" - IL_0062: ldloc.3 - IL_0063: box ""T"" - IL_0068: brtrue.s IL_0072 - IL_006a: ldarg.0 - IL_006b: ldflda ""T Program.d__2.<>7__wrap1"" - IL_0070: br.s IL_0078 - IL_0072: ldarg.0 - IL_0073: ldflda ""T Program.d__2.item"" - IL_0078: ldarg.0 - IL_0079: ldfld ""int Program.d__2.<>7__wrap2"" - IL_007e: constrained. ""T"" - IL_0084: callvirt ""int? IMoveable.this[int].get"" - IL_0089: stloc.1 - IL_008a: ldloca.s V_1 - IL_008c: call ""readonly int int?.GetValueOrDefault()"" - IL_0091: stloc.2 - IL_0092: ldloca.s V_1 - IL_0094: call ""readonly bool int?.HasValue.get"" - IL_0099: brtrue IL_013f - IL_009e: ldarg.0 - IL_009f: ldflda ""T Program.d__2.item"" - IL_00a4: call ""int Program.GetOffset(ref T)"" - IL_00a9: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" - IL_00ae: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_00b3: stloc.s V_4 - IL_00b5: ldloca.s V_4 - IL_00b7: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_00bc: brtrue.s IL_00ff - IL_00be: ldarg.0 - IL_00bf: ldc.i4.0 - IL_00c0: dup - IL_00c1: stloc.0 - IL_00c2: stfld ""int Program.d__2.<>1__state"" - IL_00c7: ldarg.0 - IL_00c8: ldloc.s V_4 - IL_00ca: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_00cf: ldarg.0 - IL_00d0: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_00d5: ldloca.s V_4 - IL_00d7: ldarg.0 - IL_00d8: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" - IL_00dd: leave IL_0179 - IL_00e2: ldarg.0 - IL_00e3: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_00e8: stloc.s V_4 + IL_001f: ldarg.0 + IL_0020: ldfld ""T Program.d__2.item"" + IL_0025: stfld ""T Program.d__2.<>7__wrap1"" + IL_002a: ldarg.0 + IL_002b: ldtoken ""T"" + IL_0030: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0035: call ""bool System.Type.IsValueType.get"" + IL_003a: brtrue.s IL_0044 + IL_003c: ldarg.0 + IL_003d: ldflda ""T Program.d__2.<>7__wrap1"" + IL_0042: br.s IL_004a + IL_0044: ldarg.0 + IL_0045: ldflda ""T Program.d__2.item"" + IL_004a: constrained. ""T"" + IL_0050: callvirt ""int IMoveable.Length.get"" + IL_0055: ldc.i4.1 + IL_0056: sub + IL_0057: stfld ""int Program.d__2.<>7__wrap2"" + IL_005c: ldtoken ""T"" + IL_0061: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0066: call ""bool System.Type.IsValueType.get"" + IL_006b: brtrue.s IL_0075 + IL_006d: ldarg.0 + IL_006e: ldflda ""T Program.d__2.<>7__wrap1"" + IL_0073: br.s IL_007b + IL_0075: ldarg.0 + IL_0076: ldflda ""T Program.d__2.item"" + IL_007b: ldarg.0 + IL_007c: ldfld ""int Program.d__2.<>7__wrap2"" + IL_0081: constrained. ""T"" + IL_0087: callvirt ""int? IMoveable.this[int].get"" + IL_008c: stloc.1 + IL_008d: ldloca.s V_1 + IL_008f: call ""readonly int int?.GetValueOrDefault()"" + IL_0094: stloc.2 + IL_0095: ldloca.s V_1 + IL_0097: call ""readonly bool int?.HasValue.get"" + IL_009c: brtrue IL_0140 + IL_00a1: ldarg.0 + IL_00a2: ldflda ""T Program.d__2.item"" + IL_00a7: call ""int Program.GetOffset(ref T)"" + IL_00ac: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" + IL_00b1: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_00b6: stloc.3 + IL_00b7: ldloca.s V_3 + IL_00b9: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_00be: brtrue.s IL_00ff + IL_00c0: ldarg.0 + IL_00c1: ldc.i4.0 + IL_00c2: dup + IL_00c3: stloc.0 + IL_00c4: stfld ""int Program.d__2.<>1__state"" + IL_00c9: ldarg.0 + IL_00ca: ldloc.3 + IL_00cb: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_00d0: ldarg.0 + IL_00d1: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_00d6: ldloca.s V_3 + IL_00d8: ldarg.0 + IL_00d9: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" + IL_00de: leave IL_017a + IL_00e3: ldarg.0 + IL_00e4: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_00e9: stloc.3 IL_00ea: ldarg.0 IL_00eb: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" IL_00f0: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" @@ -24935,51 +24750,50 @@ .locals init (int V_0, IL_00f8: dup IL_00f9: stloc.0 IL_00fa: stfld ""int Program.d__2.<>1__state"" - IL_00ff: ldloca.s V_4 + IL_00ff: ldloca.s V_3 IL_0101: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" IL_0106: stloc.2 - IL_0107: ldloca.s V_3 - IL_0109: initobj ""T"" - IL_010f: ldloc.3 - IL_0110: box ""T"" - IL_0115: brtrue.s IL_011f - IL_0117: ldarg.0 - IL_0118: ldflda ""T Program.d__2.<>7__wrap1"" - IL_011d: br.s IL_0125 - IL_011f: ldarg.0 - IL_0120: ldflda ""T Program.d__2.item"" - IL_0125: ldarg.0 - IL_0126: ldfld ""int Program.d__2.<>7__wrap2"" - IL_012b: ldloc.2 - IL_012c: newobj ""int?..ctor(int)"" - IL_0131: dup - IL_0132: stloc.s V_5 - IL_0134: constrained. ""T"" - IL_013a: callvirt ""void IMoveable.this[int].set"" - IL_013f: ldarg.0 - IL_0140: ldflda ""T Program.d__2.<>7__wrap1"" - IL_0145: initobj ""T"" - IL_014b: leave.s IL_0166 + IL_0107: ldtoken ""T"" + IL_010c: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0111: call ""bool System.Type.IsValueType.get"" + IL_0116: brtrue.s IL_0120 + IL_0118: ldarg.0 + IL_0119: ldflda ""T Program.d__2.<>7__wrap1"" + IL_011e: br.s IL_0126 + IL_0120: ldarg.0 + IL_0121: ldflda ""T Program.d__2.item"" + IL_0126: ldarg.0 + IL_0127: ldfld ""int Program.d__2.<>7__wrap2"" + IL_012c: ldloc.2 + IL_012d: newobj ""int?..ctor(int)"" + IL_0132: dup + IL_0133: stloc.s V_4 + IL_0135: constrained. ""T"" + IL_013b: callvirt ""void IMoveable.this[int].set"" + IL_0140: ldarg.0 + IL_0141: ldflda ""T Program.d__2.<>7__wrap1"" + IL_0146: initobj ""T"" + IL_014c: leave.s IL_0167 } catch System.Exception { - IL_014d: stloc.s V_6 - IL_014f: ldarg.0 - IL_0150: ldc.i4.s -2 - IL_0152: stfld ""int Program.d__2.<>1__state"" - IL_0157: ldarg.0 - IL_0158: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_015d: ldloc.s V_6 - IL_015f: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" - IL_0164: leave.s IL_0179 + IL_014e: stloc.s V_5 + IL_0150: ldarg.0 + IL_0151: ldc.i4.s -2 + IL_0153: stfld ""int Program.d__2.<>1__state"" + IL_0158: ldarg.0 + IL_0159: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_015e: ldloc.s V_5 + IL_0160: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" + IL_0165: leave.s IL_017a } - IL_0166: ldarg.0 - IL_0167: ldc.i4.s -2 - IL_0169: stfld ""int Program.d__2.<>1__state"" - IL_016e: ldarg.0 - IL_016f: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_0174: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" - IL_0179: ret + IL_0167: ldarg.0 + IL_0168: ldc.i4.s -2 + IL_016a: stfld ""int Program.d__2.<>1__state"" + IL_016f: ldarg.0 + IL_0170: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_0175: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" + IL_017a: ret } "); } @@ -25320,14 +25134,12 @@ .locals init (T& V_0, int V_4, int? V_5, int V_6, - T V_7, - int? V_8) + int? V_7) IL_0000: ldarga.s V_0 IL_0002: stloc.2 - IL_0003: ldloca.s V_7 - IL_0005: initobj ""T"" - IL_000b: ldloc.s V_7 - IL_000d: box ""T"" + IL_0003: ldtoken ""T"" + IL_0008: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000d: call ""bool System.Type.IsValueType.get"" IL_0012: brtrue.s IL_001f IL_0014: ldloc.2 IL_0015: ldobj ""T"" @@ -25361,10 +25173,10 @@ .locals init (T& V_0, IL_0062: stloc.s V_6 IL_0064: ldloc.0 IL_0065: ldloc.s V_4 - IL_0067: ldloca.s V_8 + IL_0067: ldloca.s V_7 IL_0069: ldloc.s V_6 IL_006b: call ""int?..ctor(int)"" - IL_0070: ldloc.s V_8 + IL_0070: ldloc.s V_7 IL_0072: constrained. ""T"" IL_0078: callvirt ""void IMoveable.this[int].set"" IL_007d: ret @@ -25640,14 +25452,12 @@ .locals init (T& V_0, int V_4, int? V_5, int V_6, - T V_7, - int? V_8) + int? V_7) IL_0000: ldarg.0 IL_0001: stloc.2 - IL_0002: ldloca.s V_7 - IL_0004: initobj ""T"" - IL_000a: ldloc.s V_7 - IL_000c: box ""T"" + IL_0002: ldtoken ""T"" + IL_0007: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000c: call ""bool System.Type.IsValueType.get"" IL_0011: brtrue.s IL_001e IL_0013: ldloc.2 IL_0014: ldobj ""T"" @@ -25681,10 +25491,10 @@ .locals init (T& V_0, IL_005f: stloc.s V_6 IL_0061: ldloc.0 IL_0062: ldloc.s V_4 - IL_0064: ldloca.s V_8 + IL_0064: ldloca.s V_7 IL_0066: ldloc.s V_6 IL_0068: call ""int?..ctor(int)"" - IL_006d: ldloc.s V_8 + IL_006d: ldloc.s V_7 IL_006f: constrained. ""T"" IL_0075: callvirt ""void IMoveable.this[int].set"" IL_007a: ret @@ -26037,10 +25847,9 @@ .locals init (int V_0, int V_1, int? V_2, int V_3, - T V_4, - System.Runtime.CompilerServices.TaskAwaiter V_5, - int? V_6, - System.Exception V_7) + System.Runtime.CompilerServices.TaskAwaiter V_4, + int? V_5, + System.Exception V_6) IL_0000: ldarg.0 IL_0001: ldfld ""int Program.d__2.<>1__state"" IL_0006: stloc.0 @@ -26048,10 +25857,9 @@ .locals init (int V_0, { IL_0007: ldloc.0 IL_0008: brfalse IL_00f1 - IL_000d: ldloca.s V_4 - IL_000f: initobj ""T"" - IL_0015: ldloc.s V_4 - IL_0017: box ""T"" + IL_000d: ldtoken ""T"" + IL_0012: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0017: call ""bool System.Type.IsValueType.get"" IL_001c: brtrue.s IL_002a IL_001e: ldarg.0 IL_001f: ldarg.0 @@ -26062,10 +25870,9 @@ .locals init (int V_0, IL_0030: call ""int Program.GetOffset(ref T)"" IL_0035: stloc.1 IL_0036: ldarg.0 - IL_0037: ldloca.s V_4 - IL_0039: initobj ""T"" - IL_003f: ldloc.s V_4 - IL_0041: box ""T"" + IL_0037: ldtoken ""T"" + IL_003c: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0041: call ""bool System.Type.IsValueType.get"" IL_0046: brtrue.s IL_0050 IL_0048: ldarg.0 IL_0049: ldflda ""T Program.d__2.<>7__wrap1"" @@ -26077,10 +25884,9 @@ .locals init (int V_0, IL_0061: ldloc.1 IL_0062: sub IL_0063: stfld ""int Program.d__2.<>7__wrap2"" - IL_0068: ldloca.s V_4 - IL_006a: initobj ""T"" - IL_0070: ldloc.s V_4 - IL_0072: box ""T"" + IL_0068: ldtoken ""T"" + IL_006d: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0072: call ""bool System.Type.IsValueType.get"" IL_0077: brtrue.s IL_0081 IL_0079: ldarg.0 IL_007a: ldflda ""T Program.d__2.<>7__wrap1"" @@ -26103,8 +25909,8 @@ .locals init (int V_0, IL_00b3: call ""int Program.GetOffset(ref T)"" IL_00b8: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" IL_00bd: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_00c2: stloc.s V_5 - IL_00c4: ldloca.s V_5 + IL_00c2: stloc.s V_4 + IL_00c4: ldloca.s V_4 IL_00c6: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" IL_00cb: brtrue.s IL_010e IL_00cd: ldarg.0 @@ -26113,17 +25919,17 @@ .locals init (int V_0, IL_00d0: stloc.0 IL_00d1: stfld ""int Program.d__2.<>1__state"" IL_00d6: ldarg.0 - IL_00d7: ldloc.s V_5 + IL_00d7: ldloc.s V_4 IL_00d9: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" IL_00de: ldarg.0 IL_00df: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_00e4: ldloca.s V_5 + IL_00e4: ldloca.s V_4 IL_00e6: ldarg.0 IL_00e7: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" IL_00ec: leave IL_0189 IL_00f1: ldarg.0 IL_00f2: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_00f7: stloc.s V_5 + IL_00f7: stloc.s V_4 IL_00f9: ldarg.0 IL_00fa: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" IL_00ff: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" @@ -26132,13 +25938,12 @@ .locals init (int V_0, IL_0107: dup IL_0108: stloc.0 IL_0109: stfld ""int Program.d__2.<>1__state"" - IL_010e: ldloca.s V_5 + IL_010e: ldloca.s V_4 IL_0110: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" IL_0115: stloc.3 - IL_0116: ldloca.s V_4 - IL_0118: initobj ""T"" - IL_011e: ldloc.s V_4 - IL_0120: box ""T"" + IL_0116: ldtoken ""T"" + IL_011b: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0120: call ""bool System.Type.IsValueType.get"" IL_0125: brtrue.s IL_012f IL_0127: ldarg.0 IL_0128: ldflda ""T Program.d__2.<>7__wrap1"" @@ -26150,7 +25955,7 @@ .locals init (int V_0, IL_013b: ldloc.3 IL_013c: newobj ""int?..ctor(int)"" IL_0141: dup - IL_0142: stloc.s V_6 + IL_0142: stloc.s V_5 IL_0144: constrained. ""T"" IL_014a: callvirt ""void IMoveable.this[int].set"" IL_014f: ldarg.0 @@ -26160,13 +25965,13 @@ .locals init (int V_0, } catch System.Exception { - IL_015d: stloc.s V_7 + IL_015d: stloc.s V_6 IL_015f: ldarg.0 IL_0160: ldc.i4.s -2 IL_0162: stfld ""int Program.d__2.<>1__state"" IL_0167: ldarg.0 IL_0168: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_016d: ldloc.s V_7 + IL_016d: ldloc.s V_6 IL_016f: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" IL_0174: leave.s IL_0189 } @@ -26599,10 +26404,9 @@ .locals init (int V_0, int V_2, int? V_3, int V_4, - T V_5, - System.Runtime.CompilerServices.TaskAwaiter V_6, - int? V_7, - System.Exception V_8) + System.Runtime.CompilerServices.TaskAwaiter V_5, + int? V_6, + System.Exception V_7) IL_0000: ldarg.0 IL_0001: ldfld ""int Program.d__2.<>1__state"" IL_0006: stloc.0 @@ -26610,10 +26414,9 @@ .locals init (int V_0, { IL_0007: ldloc.0 IL_0008: brfalse.s IL_006b - IL_000a: ldloca.s V_5 - IL_000c: initobj ""T"" - IL_0012: ldloc.s V_5 - IL_0014: box ""T"" + IL_000a: ldtoken ""T"" + IL_000f: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0014: call ""bool System.Type.IsValueType.get"" IL_0019: brtrue.s IL_0027 IL_001b: ldarg.0 IL_001c: ldarg.0 @@ -26624,8 +26427,8 @@ .locals init (int V_0, IL_002d: call ""int Program.GetOffset(ref T)"" IL_0032: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" IL_0037: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_003c: stloc.s V_6 - IL_003e: ldloca.s V_6 + IL_003c: stloc.s V_5 + IL_003e: ldloca.s V_5 IL_0040: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" IL_0045: brtrue.s IL_0088 IL_0047: ldarg.0 @@ -26634,17 +26437,17 @@ .locals init (int V_0, IL_004a: stloc.0 IL_004b: stfld ""int Program.d__2.<>1__state"" IL_0050: ldarg.0 - IL_0051: ldloc.s V_6 + IL_0051: ldloc.s V_5 IL_0053: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" IL_0058: ldarg.0 IL_0059: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_005e: ldloca.s V_6 + IL_005e: ldloca.s V_5 IL_0060: ldarg.0 IL_0061: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" IL_0066: leave IL_0177 IL_006b: ldarg.0 IL_006c: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_0071: stloc.s V_6 + IL_0071: stloc.s V_5 IL_0073: ldarg.0 IL_0074: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" IL_0079: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" @@ -26653,13 +26456,12 @@ .locals init (int V_0, IL_0081: dup IL_0082: stloc.0 IL_0083: stfld ""int Program.d__2.<>1__state"" - IL_0088: ldloca.s V_6 + IL_0088: ldloca.s V_5 IL_008a: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" IL_008f: stloc.1 - IL_0090: ldloca.s V_5 - IL_0092: initobj ""T"" - IL_0098: ldloc.s V_5 - IL_009a: box ""T"" + IL_0090: ldtoken ""T"" + IL_0095: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_009a: call ""bool System.Type.IsValueType.get"" IL_009f: brtrue.s IL_00a9 IL_00a1: ldarg.0 IL_00a2: ldflda ""T Program.d__2.<>7__wrap1"" @@ -26671,10 +26473,9 @@ .locals init (int V_0, IL_00ba: ldloc.1 IL_00bb: sub IL_00bc: stloc.2 - IL_00bd: ldloca.s V_5 - IL_00bf: initobj ""T"" - IL_00c5: ldloc.s V_5 - IL_00c7: box ""T"" + IL_00bd: ldtoken ""T"" + IL_00c2: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_00c7: call ""bool System.Type.IsValueType.get"" IL_00cc: brtrue.s IL_00d6 IL_00ce: ldarg.0 IL_00cf: ldflda ""T Program.d__2.<>7__wrap1"" @@ -26695,10 +26496,9 @@ .locals init (int V_0, IL_00fc: ldflda ""T Program.d__2.item"" IL_0101: call ""int Program.GetOffset(ref T)"" IL_0106: stloc.s V_4 - IL_0108: ldloca.s V_5 - IL_010a: initobj ""T"" - IL_0110: ldloc.s V_5 - IL_0112: box ""T"" + IL_0108: ldtoken ""T"" + IL_010d: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0112: call ""bool System.Type.IsValueType.get"" IL_0117: brtrue.s IL_0121 IL_0119: ldarg.0 IL_011a: ldflda ""T Program.d__2.<>7__wrap1"" @@ -26709,7 +26509,7 @@ .locals init (int V_0, IL_0128: ldloc.s V_4 IL_012a: newobj ""int?..ctor(int)"" IL_012f: dup - IL_0130: stloc.s V_7 + IL_0130: stloc.s V_6 IL_0132: constrained. ""T"" IL_0138: callvirt ""void IMoveable.this[int].set"" IL_013d: ldarg.0 @@ -26719,13 +26519,13 @@ .locals init (int V_0, } catch System.Exception { - IL_014b: stloc.s V_8 + IL_014b: stloc.s V_7 IL_014d: ldarg.0 IL_014e: ldc.i4.s -2 IL_0150: stfld ""int Program.d__2.<>1__state"" IL_0155: ldarg.0 IL_0156: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_015b: ldloc.s V_8 + IL_015b: ldloc.s V_7 IL_015d: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" IL_0162: leave.s IL_0177 } @@ -27193,10 +26993,9 @@ .locals init (int V_0, int V_1, int? V_2, int V_3, - T V_4, - System.Runtime.CompilerServices.TaskAwaiter V_5, - int? V_6, - System.Exception V_7) + System.Runtime.CompilerServices.TaskAwaiter V_4, + int? V_5, + System.Exception V_6) IL_0000: ldarg.0 IL_0001: ldfld ""int Program.d__2.<>1__state"" IL_0006: stloc.0 @@ -27207,10 +27006,9 @@ .locals init (int V_0, IL_000a: ldloc.0 IL_000b: ldc.i4.1 IL_000c: beq IL_0152 - IL_0011: ldloca.s V_4 - IL_0013: initobj ""T"" - IL_0019: ldloc.s V_4 - IL_001b: box ""T"" + IL_0011: ldtoken ""T"" + IL_0016: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_001b: call ""bool System.Type.IsValueType.get"" IL_0020: brtrue.s IL_002e IL_0022: ldarg.0 IL_0023: ldarg.0 @@ -27221,8 +27019,8 @@ .locals init (int V_0, IL_0034: call ""int Program.GetOffset(ref T)"" IL_0039: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" IL_003e: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_0043: stloc.s V_5 - IL_0045: ldloca.s V_5 + IL_0043: stloc.s V_4 + IL_0045: ldloca.s V_4 IL_0047: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" IL_004c: brtrue.s IL_008f IL_004e: ldarg.0 @@ -27231,17 +27029,17 @@ .locals init (int V_0, IL_0051: stloc.0 IL_0052: stfld ""int Program.d__2.<>1__state"" IL_0057: ldarg.0 - IL_0058: ldloc.s V_5 + IL_0058: ldloc.s V_4 IL_005a: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" IL_005f: ldarg.0 IL_0060: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_0065: ldloca.s V_5 + IL_0065: ldloca.s V_4 IL_0067: ldarg.0 IL_0068: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" IL_006d: leave IL_01ea IL_0072: ldarg.0 IL_0073: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_0078: stloc.s V_5 + IL_0078: stloc.s V_4 IL_007a: ldarg.0 IL_007b: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" IL_0080: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" @@ -27250,14 +27048,13 @@ .locals init (int V_0, IL_0088: dup IL_0089: stloc.0 IL_008a: stfld ""int Program.d__2.<>1__state"" - IL_008f: ldloca.s V_5 + IL_008f: ldloca.s V_4 IL_0091: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" IL_0096: stloc.1 IL_0097: ldarg.0 - IL_0098: ldloca.s V_4 - IL_009a: initobj ""T"" - IL_00a0: ldloc.s V_4 - IL_00a2: box ""T"" + IL_0098: ldtoken ""T"" + IL_009d: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_00a2: call ""bool System.Type.IsValueType.get"" IL_00a7: brtrue.s IL_00b1 IL_00a9: ldarg.0 IL_00aa: ldflda ""T Program.d__2.<>7__wrap1"" @@ -27269,10 +27066,9 @@ .locals init (int V_0, IL_00c2: ldloc.1 IL_00c3: sub IL_00c4: stfld ""int Program.d__2.<>7__wrap2"" - IL_00c9: ldloca.s V_4 - IL_00cb: initobj ""T"" - IL_00d1: ldloc.s V_4 - IL_00d3: box ""T"" + IL_00c9: ldtoken ""T"" + IL_00ce: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_00d3: call ""bool System.Type.IsValueType.get"" IL_00d8: brtrue.s IL_00e2 IL_00da: ldarg.0 IL_00db: ldflda ""T Program.d__2.<>7__wrap1"" @@ -27295,8 +27091,8 @@ .locals init (int V_0, IL_0114: call ""int Program.GetOffset(ref T)"" IL_0119: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" IL_011e: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_0123: stloc.s V_5 - IL_0125: ldloca.s V_5 + IL_0123: stloc.s V_4 + IL_0125: ldloca.s V_4 IL_0127: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" IL_012c: brtrue.s IL_016f IL_012e: ldarg.0 @@ -27305,17 +27101,17 @@ .locals init (int V_0, IL_0131: stloc.0 IL_0132: stfld ""int Program.d__2.<>1__state"" IL_0137: ldarg.0 - IL_0138: ldloc.s V_5 + IL_0138: ldloc.s V_4 IL_013a: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" IL_013f: ldarg.0 IL_0140: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_0145: ldloca.s V_5 + IL_0145: ldloca.s V_4 IL_0147: ldarg.0 IL_0148: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" IL_014d: leave IL_01ea IL_0152: ldarg.0 IL_0153: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_0158: stloc.s V_5 + IL_0158: stloc.s V_4 IL_015a: ldarg.0 IL_015b: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" IL_0160: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" @@ -27324,13 +27120,12 @@ .locals init (int V_0, IL_0168: dup IL_0169: stloc.0 IL_016a: stfld ""int Program.d__2.<>1__state"" - IL_016f: ldloca.s V_5 + IL_016f: ldloca.s V_4 IL_0171: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" IL_0176: stloc.3 - IL_0177: ldloca.s V_4 - IL_0179: initobj ""T"" - IL_017f: ldloc.s V_4 - IL_0181: box ""T"" + IL_0177: ldtoken ""T"" + IL_017c: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0181: call ""bool System.Type.IsValueType.get"" IL_0186: brtrue.s IL_0190 IL_0188: ldarg.0 IL_0189: ldflda ""T Program.d__2.<>7__wrap1"" @@ -27342,7 +27137,7 @@ .locals init (int V_0, IL_019c: ldloc.3 IL_019d: newobj ""int?..ctor(int)"" IL_01a2: dup - IL_01a3: stloc.s V_6 + IL_01a3: stloc.s V_5 IL_01a5: constrained. ""T"" IL_01ab: callvirt ""void IMoveable.this[int].set"" IL_01b0: ldarg.0 @@ -27352,13 +27147,13 @@ .locals init (int V_0, } catch System.Exception { - IL_01be: stloc.s V_7 + IL_01be: stloc.s V_6 IL_01c0: ldarg.0 IL_01c1: ldc.i4.s -2 IL_01c3: stfld ""int Program.d__2.<>1__state"" IL_01c8: ldarg.0 IL_01c9: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_01ce: ldloc.s V_7 + IL_01ce: ldloc.s V_6 IL_01d0: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" IL_01d5: leave.s IL_01ea } @@ -27722,33 +27517,31 @@ .maxstack 3 .locals init (T V_0, T& V_1, int V_2, - T V_3, - int? V_4) + int? V_3) IL_0000: ldarga.s V_0 IL_0002: stloc.1 - IL_0003: ldloca.s V_3 - IL_0005: initobj ""T"" - IL_000b: ldloc.3 - IL_000c: box ""T"" - IL_0011: brtrue.s IL_001e - IL_0013: ldloc.1 - IL_0014: ldobj ""T"" - IL_0019: stloc.0 - IL_001a: ldloca.s V_0 - IL_001c: br.s IL_001f - IL_001e: ldloc.1 - IL_001f: dup - IL_0020: constrained. ""T"" - IL_0026: callvirt ""int IMoveable.Length.get"" - IL_002b: ldc.i4.1 - IL_002c: sub - IL_002d: stloc.2 - IL_002e: ldloca.s V_4 - IL_0030: ldarga.s V_0 - IL_0032: call ""int Program.GetOffset(ref T)"" - IL_0037: call ""int?..ctor(int)"" - IL_003c: ldloc.2 - IL_003d: ldloc.s V_4 + IL_0003: ldtoken ""T"" + IL_0008: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000d: call ""bool System.Type.IsValueType.get"" + IL_0012: brtrue.s IL_001f + IL_0014: ldloc.1 + IL_0015: ldobj ""T"" + IL_001a: stloc.0 + IL_001b: ldloca.s V_0 + IL_001d: br.s IL_0020 + IL_001f: ldloc.1 + IL_0020: dup + IL_0021: constrained. ""T"" + IL_0027: callvirt ""int IMoveable.Length.get"" + IL_002c: ldc.i4.1 + IL_002d: sub + IL_002e: stloc.2 + IL_002f: ldloca.s V_3 + IL_0031: ldarga.s V_0 + IL_0033: call ""int Program.GetOffset(ref T)"" + IL_0038: call ""int?..ctor(int)"" + IL_003d: ldloc.2 + IL_003e: ldloc.3 IL_003f: constrained. ""T"" IL_0045: callvirt ""void IMoveable.this[int].set"" IL_004a: ret @@ -27972,33 +27765,31 @@ .maxstack 3 .locals init (T V_0, T& V_1, int V_2, - T V_3, - int? V_4) + int? V_3) IL_0000: ldarg.0 IL_0001: stloc.1 - IL_0002: ldloca.s V_3 - IL_0004: initobj ""T"" - IL_000a: ldloc.3 - IL_000b: box ""T"" - IL_0010: brtrue.s IL_001d - IL_0012: ldloc.1 - IL_0013: ldobj ""T"" - IL_0018: stloc.0 - IL_0019: ldloca.s V_0 - IL_001b: br.s IL_001e - IL_001d: ldloc.1 - IL_001e: dup - IL_001f: constrained. ""T"" - IL_0025: callvirt ""int IMoveable.Length.get"" - IL_002a: ldc.i4.1 - IL_002b: sub - IL_002c: stloc.2 - IL_002d: ldloca.s V_4 - IL_002f: ldarg.0 - IL_0030: call ""int Program.GetOffset(ref T)"" - IL_0035: call ""int?..ctor(int)"" - IL_003a: ldloc.2 - IL_003b: ldloc.s V_4 + IL_0002: ldtoken ""T"" + IL_0007: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000c: call ""bool System.Type.IsValueType.get"" + IL_0011: brtrue.s IL_001e + IL_0013: ldloc.1 + IL_0014: ldobj ""T"" + IL_0019: stloc.0 + IL_001a: ldloca.s V_0 + IL_001c: br.s IL_001f + IL_001e: ldloc.1 + IL_001f: dup + IL_0020: constrained. ""T"" + IL_0026: callvirt ""int IMoveable.Length.get"" + IL_002b: ldc.i4.1 + IL_002c: sub + IL_002d: stloc.2 + IL_002e: ldloca.s V_3 + IL_0030: ldarg.0 + IL_0031: call ""int Program.GetOffset(ref T)"" + IL_0036: call ""int?..ctor(int)"" + IL_003b: ldloc.2 + IL_003c: ldloc.3 IL_003d: constrained. ""T"" IL_0043: callvirt ""void IMoveable.this[int].set"" IL_0048: ret @@ -28305,9 +28096,8 @@ .maxstack 3 .locals init (int V_0, int V_1, int? V_2, - T V_3, - System.Runtime.CompilerServices.TaskAwaiter V_4, - System.Exception V_5) + System.Runtime.CompilerServices.TaskAwaiter V_3, + System.Exception V_4) IL_0000: ldarg.0 IL_0001: ldfld ""int Program.d__2.<>1__state"" IL_0006: stloc.0 @@ -28315,75 +28105,72 @@ .locals init (int V_0, { IL_0007: ldloc.0 IL_0008: brfalse IL_009e - IL_000d: ldloca.s V_3 - IL_000f: initobj ""T"" - IL_0015: ldloc.3 - IL_0016: box ""T"" - IL_001b: brtrue.s IL_0029 - IL_001d: ldarg.0 + IL_000d: ldtoken ""T"" + IL_0012: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0017: call ""bool System.Type.IsValueType.get"" + IL_001c: brtrue.s IL_002a IL_001e: ldarg.0 - IL_001f: ldfld ""T Program.d__2.item"" - IL_0024: stfld ""T Program.d__2.<>7__wrap1"" - IL_0029: ldarg.0 - IL_002a: ldloca.s V_3 - IL_002c: initobj ""T"" - IL_0032: ldloc.3 - IL_0033: box ""T"" - IL_0038: brtrue.s IL_0042 - IL_003a: ldarg.0 - IL_003b: ldflda ""T Program.d__2.<>7__wrap1"" - IL_0040: br.s IL_0048 - IL_0042: ldarg.0 - IL_0043: ldflda ""T Program.d__2.item"" - IL_0048: constrained. ""T"" - IL_004e: callvirt ""int IMoveable.Length.get"" - IL_0053: ldc.i4.1 - IL_0054: sub - IL_0055: stfld ""int Program.d__2.<>7__wrap2"" - IL_005a: ldarg.0 - IL_005b: ldflda ""T Program.d__2.item"" - IL_0060: call ""int Program.GetOffset(ref T)"" - IL_0065: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" - IL_006a: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_006f: stloc.s V_4 - IL_0071: ldloca.s V_4 - IL_0073: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_0078: brtrue.s IL_00bb - IL_007a: ldarg.0 - IL_007b: ldc.i4.0 - IL_007c: dup - IL_007d: stloc.0 - IL_007e: stfld ""int Program.d__2.<>1__state"" - IL_0083: ldarg.0 - IL_0084: ldloc.s V_4 + IL_001f: ldarg.0 + IL_0020: ldfld ""T Program.d__2.item"" + IL_0025: stfld ""T Program.d__2.<>7__wrap1"" + IL_002a: ldarg.0 + IL_002b: ldtoken ""T"" + IL_0030: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0035: call ""bool System.Type.IsValueType.get"" + IL_003a: brtrue.s IL_0044 + IL_003c: ldarg.0 + IL_003d: ldflda ""T Program.d__2.<>7__wrap1"" + IL_0042: br.s IL_004a + IL_0044: ldarg.0 + IL_0045: ldflda ""T Program.d__2.item"" + IL_004a: constrained. ""T"" + IL_0050: callvirt ""int IMoveable.Length.get"" + IL_0055: ldc.i4.1 + IL_0056: sub + IL_0057: stfld ""int Program.d__2.<>7__wrap2"" + IL_005c: ldarg.0 + IL_005d: ldflda ""T Program.d__2.item"" + IL_0062: call ""int Program.GetOffset(ref T)"" + IL_0067: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" + IL_006c: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_0071: stloc.3 + IL_0072: ldloca.s V_3 + IL_0074: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_0079: brtrue.s IL_00ba + IL_007b: ldarg.0 + IL_007c: ldc.i4.0 + IL_007d: dup + IL_007e: stloc.0 + IL_007f: stfld ""int Program.d__2.<>1__state"" + IL_0084: ldarg.0 + IL_0085: ldloc.3 IL_0086: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" IL_008b: ldarg.0 IL_008c: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_0091: ldloca.s V_4 + IL_0091: ldloca.s V_3 IL_0093: ldarg.0 IL_0094: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" IL_0099: leave IL_0134 IL_009e: ldarg.0 IL_009f: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_00a4: stloc.s V_4 - IL_00a6: ldarg.0 - IL_00a7: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_00ac: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_00b2: ldarg.0 - IL_00b3: ldc.i4.m1 - IL_00b4: dup - IL_00b5: stloc.0 - IL_00b6: stfld ""int Program.d__2.<>1__state"" - IL_00bb: ldloca.s V_4 - IL_00bd: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_00c2: stloc.1 - IL_00c3: ldloc.1 - IL_00c4: newobj ""int?..ctor(int)"" - IL_00c9: stloc.2 - IL_00ca: ldloca.s V_3 - IL_00cc: initobj ""T"" - IL_00d2: ldloc.3 - IL_00d3: box ""T"" + IL_00a4: stloc.3 + IL_00a5: ldarg.0 + IL_00a6: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_00ab: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_00b1: ldarg.0 + IL_00b2: ldc.i4.m1 + IL_00b3: dup + IL_00b4: stloc.0 + IL_00b5: stfld ""int Program.d__2.<>1__state"" + IL_00ba: ldloca.s V_3 + IL_00bc: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_00c1: stloc.1 + IL_00c2: ldloc.1 + IL_00c3: newobj ""int?..ctor(int)"" + IL_00c8: stloc.2 + IL_00c9: ldtoken ""T"" + IL_00ce: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_00d3: call ""bool System.Type.IsValueType.get"" IL_00d8: brtrue.s IL_00e2 IL_00da: ldarg.0 IL_00db: ldflda ""T Program.d__2.<>7__wrap1"" @@ -28402,13 +28189,13 @@ .locals init (int V_0, } catch System.Exception { - IL_0108: stloc.s V_5 + IL_0108: stloc.s V_4 IL_010a: ldarg.0 IL_010b: ldc.i4.s -2 IL_010d: stfld ""int Program.d__2.<>1__state"" IL_0112: ldarg.0 IL_0113: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_0118: ldloc.s V_5 + IL_0118: ldloc.s V_4 IL_011a: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" IL_011f: leave.s IL_0134 } @@ -28708,14 +28495,12 @@ .maxstack 4 .locals init (T& V_0, T V_1, T& V_2, - int V_3, - T V_4) + int V_3) IL_0000: ldarga.s V_0 IL_0002: stloc.2 - IL_0003: ldloca.s V_4 - IL_0005: initobj ""T"" - IL_000b: ldloc.s V_4 - IL_000d: box ""T"" + IL_0003: ldtoken ""T"" + IL_0008: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000d: call ""bool System.Type.IsValueType.get"" IL_0012: brtrue.s IL_001f IL_0014: ldloc.2 IL_0015: ldobj ""T"" @@ -28942,16 +28727,14 @@ .locals init (T V_0, // Code size 68 (0x44) .maxstack 4 .locals init (T& V_0, - T V_1, - T& V_2, - int V_3, - T V_4) + T V_1, + T& V_2, + int V_3) IL_0000: ldarg.0 IL_0001: stloc.2 - IL_0002: ldloca.s V_4 - IL_0004: initobj ""T"" - IL_000a: ldloc.s V_4 - IL_000c: box ""T"" + IL_0002: ldtoken ""T"" + IL_0007: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000c: call ""bool System.Type.IsValueType.get"" IL_0011: brtrue.s IL_001e IL_0013: ldloc.2 IL_0014: ldobj ""T"" @@ -29251,118 +29034,114 @@ .locals init (int V_0, verifier.VerifyIL("Program.d__2.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @" { - // Code size 285 (0x11d) + // Code size 286 (0x11e) .maxstack 4 .locals init (int V_0, int V_1, - T V_2, - System.Runtime.CompilerServices.TaskAwaiter V_3, - System.Exception V_4) + System.Runtime.CompilerServices.TaskAwaiter V_2, + System.Exception V_3) IL_0000: ldarg.0 IL_0001: ldfld ""int Program.d__2.<>1__state"" IL_0006: stloc.0 .try { IL_0007: ldloc.0 - IL_0008: brfalse.s IL_0068 - IL_000a: ldloca.s V_2 - IL_000c: initobj ""T"" - IL_0012: ldloc.2 - IL_0013: box ""T"" - IL_0018: brtrue.s IL_0026 - IL_001a: ldarg.0 + IL_0008: brfalse.s IL_0069 + IL_000a: ldtoken ""T"" + IL_000f: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0014: call ""bool System.Type.IsValueType.get"" + IL_0019: brtrue.s IL_0027 IL_001b: ldarg.0 - IL_001c: ldfld ""T Program.d__2.item"" - IL_0021: stfld ""T Program.d__2.<>7__wrap1"" - IL_0026: ldarg.0 - IL_0027: ldflda ""T Program.d__2.item"" - IL_002c: call ""int Program.GetOffset(ref T)"" - IL_0031: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" - IL_0036: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_003b: stloc.3 - IL_003c: ldloca.s V_3 - IL_003e: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_0043: brtrue.s IL_0084 - IL_0045: ldarg.0 - IL_0046: ldc.i4.0 - IL_0047: dup - IL_0048: stloc.0 - IL_0049: stfld ""int Program.d__2.<>1__state"" - IL_004e: ldarg.0 - IL_004f: ldloc.3 - IL_0050: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_0055: ldarg.0 - IL_0056: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_005b: ldloca.s V_3 - IL_005d: ldarg.0 - IL_005e: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" - IL_0063: leave IL_011c - IL_0068: ldarg.0 - IL_0069: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_006e: stloc.3 - IL_006f: ldarg.0 - IL_0070: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_0075: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_007b: ldarg.0 - IL_007c: ldc.i4.m1 - IL_007d: dup - IL_007e: stloc.0 - IL_007f: stfld ""int Program.d__2.<>1__state"" - IL_0084: ldloca.s V_3 - IL_0086: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_008b: stloc.1 - IL_008c: ldloca.s V_2 - IL_008e: initobj ""T"" - IL_0094: ldloc.2 - IL_0095: box ""T"" - IL_009a: brtrue.s IL_00a4 - IL_009c: ldarg.0 - IL_009d: ldflda ""T Program.d__2.<>7__wrap1"" - IL_00a2: br.s IL_00aa - IL_00a4: ldarg.0 - IL_00a5: ldflda ""T Program.d__2.item"" - IL_00aa: ldc.i4.0 - IL_00ab: ldloca.s V_2 - IL_00ad: initobj ""T"" - IL_00b3: ldloc.2 - IL_00b4: box ""T"" - IL_00b9: brtrue.s IL_00c3 - IL_00bb: ldarg.0 - IL_00bc: ldflda ""T Program.d__2.<>7__wrap1"" - IL_00c1: br.s IL_00c9 - IL_00c3: ldarg.0 - IL_00c4: ldflda ""T Program.d__2.item"" - IL_00c9: constrained. ""T"" - IL_00cf: callvirt ""int IMoveable.Length.get"" - IL_00d4: ldloc.1 - IL_00d5: sub - IL_00d6: constrained. ""T"" - IL_00dc: callvirt ""IMoveable IMoveable.Slice(int, int)"" - IL_00e1: pop - IL_00e2: ldarg.0 - IL_00e3: ldflda ""T Program.d__2.<>7__wrap1"" - IL_00e8: initobj ""T"" - IL_00ee: leave.s IL_0109 + IL_001c: ldarg.0 + IL_001d: ldfld ""T Program.d__2.item"" + IL_0022: stfld ""T Program.d__2.<>7__wrap1"" + IL_0027: ldarg.0 + IL_0028: ldflda ""T Program.d__2.item"" + IL_002d: call ""int Program.GetOffset(ref T)"" + IL_0032: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" + IL_0037: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_003c: stloc.2 + IL_003d: ldloca.s V_2 + IL_003f: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_0044: brtrue.s IL_0085 + IL_0046: ldarg.0 + IL_0047: ldc.i4.0 + IL_0048: dup + IL_0049: stloc.0 + IL_004a: stfld ""int Program.d__2.<>1__state"" + IL_004f: ldarg.0 + IL_0050: ldloc.2 + IL_0051: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_0056: ldarg.0 + IL_0057: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_005c: ldloca.s V_2 + IL_005e: ldarg.0 + IL_005f: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" + IL_0064: leave IL_011d + IL_0069: ldarg.0 + IL_006a: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_006f: stloc.2 + IL_0070: ldarg.0 + IL_0071: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" + IL_0076: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_007c: ldarg.0 + IL_007d: ldc.i4.m1 + IL_007e: dup + IL_007f: stloc.0 + IL_0080: stfld ""int Program.d__2.<>1__state"" + IL_0085: ldloca.s V_2 + IL_0087: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_008c: stloc.1 + IL_008d: ldtoken ""T"" + IL_0092: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0097: call ""bool System.Type.IsValueType.get"" + IL_009c: brtrue.s IL_00a6 + IL_009e: ldarg.0 + IL_009f: ldflda ""T Program.d__2.<>7__wrap1"" + IL_00a4: br.s IL_00ac + IL_00a6: ldarg.0 + IL_00a7: ldflda ""T Program.d__2.item"" + IL_00ac: ldc.i4.0 + IL_00ad: ldtoken ""T"" + IL_00b2: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_00b7: call ""bool System.Type.IsValueType.get"" + IL_00bc: brtrue.s IL_00c6 + IL_00be: ldarg.0 + IL_00bf: ldflda ""T Program.d__2.<>7__wrap1"" + IL_00c4: br.s IL_00cc + IL_00c6: ldarg.0 + IL_00c7: ldflda ""T Program.d__2.item"" + IL_00cc: constrained. ""T"" + IL_00d2: callvirt ""int IMoveable.Length.get"" + IL_00d7: ldloc.1 + IL_00d8: sub + IL_00d9: constrained. ""T"" + IL_00df: callvirt ""IMoveable IMoveable.Slice(int, int)"" + IL_00e4: pop + IL_00e5: ldarg.0 + IL_00e6: ldflda ""T Program.d__2.<>7__wrap1"" + IL_00eb: initobj ""T"" + IL_00f1: leave.s IL_010a } catch System.Exception { - IL_00f0: stloc.s V_4 - IL_00f2: ldarg.0 - IL_00f3: ldc.i4.s -2 - IL_00f5: stfld ""int Program.d__2.<>1__state"" - IL_00fa: ldarg.0 - IL_00fb: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_0100: ldloc.s V_4 - IL_0102: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" - IL_0107: leave.s IL_011c + IL_00f3: stloc.3 + IL_00f4: ldarg.0 + IL_00f5: ldc.i4.s -2 + IL_00f7: stfld ""int Program.d__2.<>1__state"" + IL_00fc: ldarg.0 + IL_00fd: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_0102: ldloc.3 + IL_0103: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" + IL_0108: leave.s IL_011d } - IL_0109: ldarg.0 - IL_010a: ldc.i4.s -2 - IL_010c: stfld ""int Program.d__2.<>1__state"" - IL_0111: ldarg.0 - IL_0112: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_0117: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" - IL_011c: ret + IL_010a: ldarg.0 + IL_010b: ldc.i4.s -2 + IL_010d: stfld ""int Program.d__2.<>1__state"" + IL_0112: ldarg.0 + IL_0113: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" + IL_0118: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" + IL_011d: ret } "); } @@ -29658,14 +29437,12 @@ .locals init (T V_0, int V_3, int V_4, int V_5, - T V_6, - System.Index V_7) + System.Index V_6) IL_0000: ldarga.s V_0 IL_0002: stloc.1 - IL_0003: ldloca.s V_6 - IL_0005: initobj ""T"" - IL_000b: ldloc.s V_6 - IL_000d: box ""T"" + IL_0003: ldtoken ""T"" + IL_0008: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000d: call ""bool System.Type.IsValueType.get"" IL_0012: brtrue.s IL_001f IL_0014: ldloc.1 IL_0015: ldobj ""T"" @@ -29682,15 +29459,15 @@ .locals init (T V_0, IL_0034: stloc.3 IL_0035: ldloca.s V_2 IL_0037: call ""System.Index System.Range.Start.get"" - IL_003c: stloc.s V_7 - IL_003e: ldloca.s V_7 + IL_003c: stloc.s V_6 + IL_003e: ldloca.s V_6 IL_0040: ldloc.3 IL_0041: call ""int System.Index.GetOffset(int)"" IL_0046: stloc.s V_4 IL_0048: ldloca.s V_2 IL_004a: call ""System.Index System.Range.End.get"" - IL_004f: stloc.s V_7 - IL_0051: ldloca.s V_7 + IL_004f: stloc.s V_6 + IL_0051: ldloca.s V_6 IL_0053: ldloc.3 IL_0054: call ""int System.Index.GetOffset(int)"" IL_0059: ldloc.s V_4 @@ -29945,14 +29722,12 @@ .locals init (T V_0, int V_3, int V_4, int V_5, - T V_6, - System.Index V_7) + System.Index V_6) IL_0000: ldarg.0 IL_0001: stloc.1 - IL_0002: ldloca.s V_6 - IL_0004: initobj ""T"" - IL_000a: ldloc.s V_6 - IL_000c: box ""T"" + IL_0002: ldtoken ""T"" + IL_0007: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000c: call ""bool System.Type.IsValueType.get"" IL_0011: brtrue.s IL_001e IL_0013: ldloc.1 IL_0014: ldobj ""T"" @@ -29969,15 +29744,15 @@ .locals init (T V_0, IL_0032: stloc.3 IL_0033: ldloca.s V_2 IL_0035: call ""System.Index System.Range.Start.get"" - IL_003a: stloc.s V_7 - IL_003c: ldloca.s V_7 + IL_003a: stloc.s V_6 + IL_003c: ldloca.s V_6 IL_003e: ldloc.3 IL_003f: call ""int System.Index.GetOffset(int)"" IL_0044: stloc.s V_4 IL_0046: ldloca.s V_2 IL_0048: call ""System.Index System.Range.End.get"" - IL_004d: stloc.s V_7 - IL_004f: ldloca.s V_7 + IL_004d: stloc.s V_6 + IL_004f: ldloca.s V_6 IL_0051: ldloc.3 IL_0052: call ""int System.Index.GetOffset(int)"" IL_0057: ldloc.s V_4 @@ -30310,10 +30085,9 @@ .locals init (int V_0, int V_2, int V_3, int V_4, - T V_5, - System.Runtime.CompilerServices.TaskAwaiter V_6, - System.Index V_7, - System.Exception V_8) + System.Runtime.CompilerServices.TaskAwaiter V_5, + System.Index V_6, + System.Exception V_7) IL_0000: ldarg.0 IL_0001: ldfld ""int Program.d__2.<>1__state"" IL_0006: stloc.0 @@ -30321,10 +30095,9 @@ .locals init (int V_0, { IL_0007: ldloc.0 IL_0008: brfalse.s IL_006b - IL_000a: ldloca.s V_5 - IL_000c: initobj ""T"" - IL_0012: ldloc.s V_5 - IL_0014: box ""T"" + IL_000a: ldtoken ""T"" + IL_000f: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0014: call ""bool System.Type.IsValueType.get"" IL_0019: brtrue.s IL_0027 IL_001b: ldarg.0 IL_001c: ldarg.0 @@ -30335,8 +30108,8 @@ .locals init (int V_0, IL_002d: call ""System.Range Program.GetOffset(ref T)"" IL_0032: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(System.Range)"" IL_0037: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_003c: stloc.s V_6 - IL_003e: ldloca.s V_6 + IL_003c: stloc.s V_5 + IL_003e: ldloca.s V_5 IL_0040: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" IL_0045: brtrue.s IL_0088 IL_0047: ldarg.0 @@ -30345,17 +30118,17 @@ .locals init (int V_0, IL_004a: stloc.0 IL_004b: stfld ""int Program.d__2.<>1__state"" IL_0050: ldarg.0 - IL_0051: ldloc.s V_6 + IL_0051: ldloc.s V_5 IL_0053: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" IL_0058: ldarg.0 IL_0059: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_005e: ldloca.s V_6 + IL_005e: ldloca.s V_5 IL_0060: ldarg.0 IL_0061: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)"" IL_0066: leave IL_014a IL_006b: ldarg.0 IL_006c: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" - IL_0071: stloc.s V_6 + IL_0071: stloc.s V_5 IL_0073: ldarg.0 IL_0074: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1"" IL_0079: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" @@ -30364,13 +30137,12 @@ .locals init (int V_0, IL_0081: dup IL_0082: stloc.0 IL_0083: stfld ""int Program.d__2.<>1__state"" - IL_0088: ldloca.s V_6 + IL_0088: ldloca.s V_5 IL_008a: call ""System.Range System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" IL_008f: stloc.1 - IL_0090: ldloca.s V_5 - IL_0092: initobj ""T"" - IL_0098: ldloc.s V_5 - IL_009a: box ""T"" + IL_0090: ldtoken ""T"" + IL_0095: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_009a: call ""bool System.Type.IsValueType.get"" IL_009f: brtrue.s IL_00a9 IL_00a1: ldarg.0 IL_00a2: ldflda ""T Program.d__2.<>7__wrap1"" @@ -30382,24 +30154,23 @@ .locals init (int V_0, IL_00ba: stloc.2 IL_00bb: ldloca.s V_1 IL_00bd: call ""System.Index System.Range.Start.get"" - IL_00c2: stloc.s V_7 - IL_00c4: ldloca.s V_7 + IL_00c2: stloc.s V_6 + IL_00c4: ldloca.s V_6 IL_00c6: ldloc.2 IL_00c7: call ""int System.Index.GetOffset(int)"" IL_00cc: stloc.3 IL_00cd: ldloca.s V_1 IL_00cf: call ""System.Index System.Range.End.get"" - IL_00d4: stloc.s V_7 - IL_00d6: ldloca.s V_7 + IL_00d4: stloc.s V_6 + IL_00d6: ldloca.s V_6 IL_00d8: ldloc.2 IL_00d9: call ""int System.Index.GetOffset(int)"" IL_00de: ldloc.3 IL_00df: sub IL_00e0: stloc.s V_4 - IL_00e2: ldloca.s V_5 - IL_00e4: initobj ""T"" - IL_00ea: ldloc.s V_5 - IL_00ec: box ""T"" + IL_00e2: ldtoken ""T"" + IL_00e7: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_00ec: call ""bool System.Type.IsValueType.get"" IL_00f1: brtrue.s IL_00fb IL_00f3: ldarg.0 IL_00f4: ldflda ""T Program.d__2.<>7__wrap1"" @@ -30418,13 +30189,13 @@ .locals init (int V_0, } catch System.Exception { - IL_011e: stloc.s V_8 + IL_011e: stloc.s V_7 IL_0120: ldarg.0 IL_0121: ldc.i4.s -2 IL_0123: stfld ""int Program.d__2.<>1__state"" IL_0128: ldarg.0 IL_0129: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder"" - IL_012e: ldloc.s V_8 + IL_012e: ldloc.s V_7 IL_0130: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" IL_0135: leave.s IL_014a } @@ -30625,5 +30396,329 @@ .locals init (int V_0, } "); } + + [Fact] + [WorkItem(66162, "https://github.com/dotnet/roslyn/issues/66162")] + public void GenericTypeParameterAsReceiver_Call_Nullable() + { + var source = @" +using System; + +#pragma warning disable CS0659 // 'Item' overrides Object.Equals(object o) but does not override Object.GetHashCode() + +struct Item +{ + public int Count; + + public override bool Equals(object obj) + { + Console.WriteLine(""Position Equals for item '{0}'"", Count); + return base.Equals(obj); + } +} + +class Program +{ + static void Main() + { + Item? item1 = new Item {Count = 1}; + Call1(item1); + Item? item2 = new Item {Count = 2}; + Call2(ref item2); + } + + static void Call1(T item) + { + item.Equals(GetOffset(ref item)); + } + + static void Call2(ref T item) + { + item.Equals(GetOffset(ref item)); + } + + static int value = 0; + static int GetOffset(ref T item) + { + item = (T)(object)new Item {Count = --value}; + return 0; + } +} +"; + var verifier = CompileAndVerify(source, options: TestOptions.ReleaseExe, expectedOutput: @" +Position Equals for item '-1' +Position Equals for item '-2' +").VerifyDiagnostics(); + + verifier.VerifyIL("Program.Call1", +@" +{ + // Code size 52 (0x34) + .maxstack 2 + .locals init (T V_0) + IL_0000: ldarga.s V_0 + IL_0002: ldtoken ""T"" + IL_0007: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000c: call ""bool System.Type.IsValueType.get"" + IL_0011: brtrue.s IL_001b + IL_0013: ldobj ""T"" + IL_0018: stloc.0 + IL_0019: ldloca.s V_0 + IL_001b: ldarga.s V_0 + IL_001d: call ""int Program.GetOffset(ref T)"" + IL_0022: box ""int"" + IL_0027: constrained. ""T"" + IL_002d: callvirt ""bool object.Equals(object)"" + IL_0032: pop + IL_0033: ret +} +"); + + verifier.VerifyIL("Program.Call2", +@" +{ + // Code size 50 (0x32) + .maxstack 2 + .locals init (T V_0) + IL_0000: ldarg.0 + IL_0001: ldtoken ""T"" + IL_0006: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000b: call ""bool System.Type.IsValueType.get"" + IL_0010: brtrue.s IL_001a + IL_0012: ldobj ""T"" + IL_0017: stloc.0 + IL_0018: ldloca.s V_0 + IL_001a: ldarg.0 + IL_001b: call ""int Program.GetOffset(ref T)"" + IL_0020: box ""int"" + IL_0025: constrained. ""T"" + IL_002b: callvirt ""bool object.Equals(object)"" + IL_0030: pop + IL_0031: ret +} +"); + + var comp = CreateCompilation(source); + comp.MakeTypeMissing(WellKnownType.System_Type); + comp.VerifyEmitDiagnostics( + // (29,9): error CS0656: Missing compiler required member 'System.Type.GetTypeFromHandle' + // item.Equals(GetOffset(ref item)); + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "item").WithArguments("System.Type", "GetTypeFromHandle").WithLocation(29, 9), + // (34,9): error CS0656: Missing compiler required member 'System.Type.GetTypeFromHandle' + // item.Equals(GetOffset(ref item)); + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "item").WithArguments("System.Type", "GetTypeFromHandle").WithLocation(34, 9) + ); + + comp = CreateCompilation(source); + comp.MakeMemberMissing(WellKnownMember.System_Type__GetTypeFromHandle); + comp.VerifyEmitDiagnostics( + // (29,9): error CS0656: Missing compiler required member 'System.Type.GetTypeFromHandle' + // item.Equals(GetOffset(ref item)); + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "item").WithArguments("System.Type", "GetTypeFromHandle").WithLocation(29, 9), + // (34,9): error CS0656: Missing compiler required member 'System.Type.GetTypeFromHandle' + // item.Equals(GetOffset(ref item)); + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "item").WithArguments("System.Type", "GetTypeFromHandle").WithLocation(34, 9) + ); + + comp = CreateCompilation(source); + comp.MakeMemberMissing(WellKnownMember.System_Type__get_IsValueType); + comp.VerifyEmitDiagnostics( + // (29,9): error CS0656: Missing compiler required member 'System.Type.get_IsValueType' + // item.Equals(GetOffset(ref item)); + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "item").WithArguments("System.Type", "get_IsValueType").WithLocation(29, 9), + // (34,9): error CS0656: Missing compiler required member 'System.Type.get_IsValueType' + // item.Equals(GetOffset(ref item)); + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "item").WithArguments("System.Type", "get_IsValueType").WithLocation(34, 9) + ); + } + + [Fact] + [WorkItem(66162, "https://github.com/dotnet/roslyn/issues/66162")] + public void GenericTypeParameterAsReceiver_Call_Nullable_Async() + { + var source = @" +using System; +using System.Threading.Tasks; + +#pragma warning disable CS0659 // 'Item' overrides Object.Equals(object o) but does not override Object.GetHashCode() + +struct Item +{ + public int Count; + + public override bool Equals(object obj) + { + Console.WriteLine(""Position Equals for item '{0}'"", Count); + return base.Equals(obj); + } +} + +class Program +{ + static async Task Main() + { + Item? item1 = new Item {Count = 1}; + await Call1(item1); + } + + static async Task Call1(T item) + { + item.Equals(await GetOffsetAsync(GetOffset(ref item))); + } + + static int value = 0; + static int GetOffset(ref T item) + { + item = (T)(object)new Item {Count = --value}; + return 0; + } + +#pragma warning disable CS1998 // This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread. + static async Task GetOffsetAsync(int i) + { + return i; + } +} +"; + + var verifier = CompileAndVerify(source, options: TestOptions.ReleaseExe, expectedOutput: @" +Position Equals for item '-1' +").VerifyDiagnostics(); + + verifier.VerifyIL("Program.d__1.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", +@" +{ + // Code size 247 (0xf7) + .maxstack 3 + .locals init (int V_0, + int V_1, + System.Runtime.CompilerServices.TaskAwaiter V_2, + System.Exception V_3) + IL_0000: ldarg.0 + IL_0001: ldfld ""int Program.d__1.<>1__state"" + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: brfalse.s IL_0069 + IL_000a: ldtoken ""T"" + IL_000f: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0014: call ""bool System.Type.IsValueType.get"" + IL_0019: brtrue.s IL_0027 + IL_001b: ldarg.0 + IL_001c: ldarg.0 + IL_001d: ldfld ""T Program.d__1.item"" + IL_0022: stfld ""T Program.d__1.<>7__wrap1"" + IL_0027: ldarg.0 + IL_0028: ldflda ""T Program.d__1.item"" + IL_002d: call ""int Program.GetOffset(ref T)"" + IL_0032: call ""System.Threading.Tasks.Task Program.GetOffsetAsync(int)"" + IL_0037: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_003c: stloc.2 + IL_003d: ldloca.s V_2 + IL_003f: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_0044: brtrue.s IL_0085 + IL_0046: ldarg.0 + IL_0047: ldc.i4.0 + IL_0048: dup + IL_0049: stloc.0 + IL_004a: stfld ""int Program.d__1.<>1__state"" + IL_004f: ldarg.0 + IL_0050: ldloc.2 + IL_0051: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__1.<>u__1"" + IL_0056: ldarg.0 + IL_0057: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__1.<>t__builder"" + IL_005c: ldloca.s V_2 + IL_005e: ldarg.0 + IL_005f: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__1>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__1)"" + IL_0064: leave IL_00f6 + IL_0069: ldarg.0 + IL_006a: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__1.<>u__1"" + IL_006f: stloc.2 + IL_0070: ldarg.0 + IL_0071: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.d__1.<>u__1"" + IL_0076: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_007c: ldarg.0 + IL_007d: ldc.i4.m1 + IL_007e: dup + IL_007f: stloc.0 + IL_0080: stfld ""int Program.d__1.<>1__state"" + IL_0085: ldloca.s V_2 + IL_0087: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_008c: stloc.1 + IL_008d: ldtoken ""T"" + IL_0092: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0097: call ""bool System.Type.IsValueType.get"" + IL_009c: brtrue.s IL_00a6 + IL_009e: ldarg.0 + IL_009f: ldflda ""T Program.d__1.<>7__wrap1"" + IL_00a4: br.s IL_00ac + IL_00a6: ldarg.0 + IL_00a7: ldflda ""T Program.d__1.item"" + IL_00ac: ldloc.1 + IL_00ad: box ""int"" + IL_00b2: constrained. ""T"" + IL_00b8: callvirt ""bool object.Equals(object)"" + IL_00bd: pop + IL_00be: ldarg.0 + IL_00bf: ldflda ""T Program.d__1.<>7__wrap1"" + IL_00c4: initobj ""T"" + IL_00ca: leave.s IL_00e3 + } + catch System.Exception + { + IL_00cc: stloc.3 + IL_00cd: ldarg.0 + IL_00ce: ldc.i4.s -2 + IL_00d0: stfld ""int Program.d__1.<>1__state"" + IL_00d5: ldarg.0 + IL_00d6: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__1.<>t__builder"" + IL_00db: ldloc.3 + IL_00dc: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" + IL_00e1: leave.s IL_00f6 + } + IL_00e3: ldarg.0 + IL_00e4: ldc.i4.s -2 + IL_00e6: stfld ""int Program.d__1.<>1__state"" + IL_00eb: ldarg.0 + IL_00ec: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__1.<>t__builder"" + IL_00f1: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" + IL_00f6: ret +} +"); + + var comp = CreateCompilation(source); + comp.MakeTypeMissing(WellKnownType.System_Type); + comp.VerifyEmitDiagnostics( + // (28,9): error CS0656: Missing compiler required member 'System.Type.GetTypeFromHandle' + // item.Equals(await GetOffsetAsync(GetOffset(ref item))); + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "item.Equals(await GetOffsetAsync(GetOffset(ref item)))").WithArguments("System.Type", "GetTypeFromHandle").WithLocation(28, 9), + // (28,9): error CS0656: Missing compiler required member 'System.Type.GetTypeFromHandle' + // item.Equals(await GetOffsetAsync(GetOffset(ref item))); + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "item.Equals(await GetOffsetAsync(GetOffset(ref item)))").WithArguments("System.Type", "GetTypeFromHandle").WithLocation(28, 9) + ); + + comp = CreateCompilation(source); + comp.MakeMemberMissing(WellKnownMember.System_Type__GetTypeFromHandle); + comp.VerifyEmitDiagnostics( + // (28,9): error CS0656: Missing compiler required member 'System.Type.GetTypeFromHandle' + // item.Equals(await GetOffsetAsync(GetOffset(ref item))); + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "item.Equals(await GetOffsetAsync(GetOffset(ref item)))").WithArguments("System.Type", "GetTypeFromHandle").WithLocation(28, 9), + // (28,9): error CS0656: Missing compiler required member 'System.Type.GetTypeFromHandle' + // item.Equals(await GetOffsetAsync(GetOffset(ref item))); + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "item.Equals(await GetOffsetAsync(GetOffset(ref item)))").WithArguments("System.Type", "GetTypeFromHandle").WithLocation(28, 9) + ); + + comp = CreateCompilation(source); + comp.MakeMemberMissing(WellKnownMember.System_Type__get_IsValueType); + comp.VerifyEmitDiagnostics( + // (28,9): error CS0656: Missing compiler required member 'System.Type.get_IsValueType' + // item.Equals(await GetOffsetAsync(GetOffset(ref item))); + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "item.Equals(await GetOffsetAsync(GetOffset(ref item)))").WithArguments("System.Type", "get_IsValueType").WithLocation(28, 9), + // (28,9): error CS0656: Missing compiler required member 'System.Type.get_IsValueType' + // item.Equals(await GetOffsetAsync(GetOffset(ref item))); + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "item.Equals(await GetOffsetAsync(GetOffset(ref item)))").WithArguments("System.Type", "get_IsValueType").WithLocation(28, 9) + ); + } } } diff --git a/src/Compilers/CSharp/Test/Emit2/Diagnostics/DiagnosticAnalyzerTests.cs b/src/Compilers/CSharp/Test/Emit2/Diagnostics/DiagnosticAnalyzerTests.cs index 583ee75b166e4..4ddae1b1fbc76 100644 --- a/src/Compilers/CSharp/Test/Emit2/Diagnostics/DiagnosticAnalyzerTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Diagnostics/DiagnosticAnalyzerTests.cs @@ -4010,19 +4010,40 @@ public record A(int X, int Y);"; Diagnostic("MyDiagnostic", @"public record A(int X, int Y);").WithLocation(2, 1)); } - [Fact, WorkItem(64771, "https://github.com/dotnet/roslyn/issues/64771")] - public void TestDisabledByDefaultAnalyzerEnabledForSingleFile() + [Theory, CombinatorialData] + [WorkItem(64771, "https://github.com/dotnet/roslyn/issues/64771")] + [WorkItem(66085, "https://github.com/dotnet/roslyn/issues/66085")] + public void TestDisabledByDefaultAnalyzerEnabledForSingleFile(bool treeBasedOptions) { var source1 = "class C1 { }"; var source2 = "class C2 { }"; var source3 = "class C3 { }"; var analyzer = new AnalyzerWithDisabledRules(); - // Enable disabled by default analyzer for first source file with analyzer config options. var compilation = CreateCompilation(new[] { source1, source2, source3 }); - var tree1 = compilation.SyntaxTrees[0]; - var options = compilation.Options.WithSyntaxTreeOptionsProvider( - new TestSyntaxTreeOptionsProvider(tree1, (AnalyzerWithDisabledRules.Rule.Id, ReportDiagnostic.Warn))); + + CSharpCompilationOptions options; + if (treeBasedOptions) + { + // Enable disabled by default analyzer for first source file with analyzer config options. + var tree1 = compilation.SyntaxTrees[0]; + options = compilation.Options.WithSyntaxTreeOptionsProvider( + new TestSyntaxTreeOptionsProvider(tree1, (AnalyzerWithDisabledRules.Rule.Id, ReportDiagnostic.Warn))); + } + else + { + // Enable disabled by default analyzer for entire compilation with SpecificDiagnosticOptions + // and disable the analyzer for second and third source file with analyzer config options. + // So, effectively the analyzer is enabled only for first source file. + var tree2 = compilation.SyntaxTrees[1]; + var tree3 = compilation.SyntaxTrees[2]; + options = compilation.Options + .WithSpecificDiagnosticOptions(ImmutableDictionary.Empty.Add(AnalyzerWithDisabledRules.Rule.Id, ReportDiagnostic.Warn)) + .WithSyntaxTreeOptionsProvider(new TestSyntaxTreeOptionsProvider( + (tree2, new[] { (AnalyzerWithDisabledRules.Rule.Id, ReportDiagnostic.Suppress) }), + (tree3, new[] { (AnalyzerWithDisabledRules.Rule.Id, ReportDiagnostic.Suppress) }))); + } + compilation = compilation.WithOptions(options); // Verify single analyzer diagnostic reported in the compilation. diff --git a/src/Compilers/CSharp/Test/Emit2/Diagnostics/OperationAnalyzerTests.cs b/src/Compilers/CSharp/Test/Emit2/Diagnostics/OperationAnalyzerTests.cs index ac5b39f318832..fa344fb23657a 100644 --- a/src/Compilers/CSharp/Test/Emit2/Diagnostics/OperationAnalyzerTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Diagnostics/OperationAnalyzerTests.cs @@ -1322,13 +1322,14 @@ public void LongArithmeticExpressionCSharp() return builder.ToString(); }; // This code will cause OperationWalker to throw `InsufficientExecutionStackException` + var expr = buildSequenceOfBinaryExpressions(8192); var source = @" class Test { public static long Calculate1(long[] f) { long x; -" + $" x = {buildSequenceOfBinaryExpressions(8192)};" + @" +" + $" x = {expr};" + @" return x; } }"; @@ -1336,8 +1337,8 @@ public static long Calculate1(long[] f) CreateCompilationWithMscorlib45(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new AssignmentOperationSyntaxTestAnalyzer() }, null, null, - Diagnostic(AssignmentOperationSyntaxTestAnalyzer.AssignmentOperationDescriptor.Id, $"x = {buildSequenceOfBinaryExpressions(8192)}").WithLocation(7, 9), - Diagnostic(AssignmentOperationSyntaxTestAnalyzer.AssignmentSyntaxDescriptor.Id, $"x = {buildSequenceOfBinaryExpressions(8192)}").WithLocation(7, 9)); + Diagnostic(AssignmentOperationSyntaxTestAnalyzer.AssignmentOperationDescriptor.Id, $"x = {expr}").WithLocation(7, 9), + Diagnostic(AssignmentOperationSyntaxTestAnalyzer.AssignmentSyntaxDescriptor.Id, $"x = {expr}").WithLocation(7, 9)); } [WorkItem(9020, "https://github.com/dotnet/roslyn/issues/9020")] diff --git a/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests_ListPatterns.cs b/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests_ListPatterns.cs index 2078ea76d3e0b..343df5fc5a17c 100644 --- a/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests_ListPatterns.cs +++ b/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests_ListPatterns.cs @@ -3090,6 +3090,163 @@ public void Test2(int[] a) ); } + [Fact, WorkItem(65876, "https://github.com/dotnet/roslyn/issues/65876")] + public void ListPattern_Negated_03() + { + var source = """ +using System; +public class C +{ + static void Main() + { + Console.WriteLine(M1(new[]{1,2})); + Console.WriteLine(M1(new[]{2,1})); + Console.WriteLine(M1(new[]{1})); + Console.WriteLine(M1(new[]{0})); + + Console.WriteLine(M2(new[]{1,2})); + Console.WriteLine(M2(new[]{2,1})); + Console.WriteLine(M2(new[]{1})); + Console.WriteLine(M2(new[]{0})); + } + + public static bool M1(int[] a) { + return a is not ([1,2,..] or [..,2,1] or [1]); + } + public static bool M2(int[] a) { + return !(a is ([1,2,..] or [..,2,1] or [1])); + } +} +"""; + var comp = CreateCompilationWithIndexAndRangeAndSpan(source, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: @" +False +False +False +True +False +False +False +True +"); + } + + [Fact] + public void ListPattern_Negated_04() + { + var source = """ +using System; +public class C +{ + static void Main() + { + Console.WriteLine(M1(new[]{1,2})); + Console.WriteLine(M1(new[]{2,1})); + Console.WriteLine(M1(new[]{1})); + Console.WriteLine(M1(new[]{0})); + + Console.WriteLine(M2(new[]{1,2})); + Console.WriteLine(M2(new[]{2,1})); + Console.WriteLine(M2(new[]{1})); + Console.WriteLine(M2(new[]{0})); + } + + public static int M1(int[] a) { + return a switch + { + not ([1,2,..] or [..,2,1] or [1]) => 1, + [1,2,..] => 2, + [..,2,1] => 3, + [1] => 4, + }; + } + public static int M2(int[] a) { + switch (a) + { + case not ([1,2,..] or [..,2,1] or [1]): + return 1; + case [1,2,..]: + return 2; + case [..,2,1]: + return 3; + case [1]: + return 4; + } + } +} +"""; + var comp = CreateCompilationWithIndexAndRangeAndSpan(source, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: @" +2 +3 +4 +1 +2 +3 +4 +1 +"); + } + + [Fact] + public void ListPattern_Negated_05() + { + var source = """ +using System; +public class C +{ + static void Main() + { + Console.WriteLine(M1(new[]{1,2}, new[]{1})); + Console.WriteLine(M1(new[]{1}, new[]{2,1})); + Console.WriteLine(M1(new[]{2,1}, new[]{1,2})); + Console.WriteLine(M1(new[]{0}, new[]{0})); + + Console.WriteLine(M2(new[]{1,2}, new[]{1})); + Console.WriteLine(M2(new[]{1}, new[]{2,1})); + Console.WriteLine(M2(new[]{2,1}, new[]{1,2})); + Console.WriteLine(M2(new[]{0}, new[]{0})); + } + + public static int M1(int[] a, int[] b) { + return (a, b) switch + { + (not ([1,2,..] or [..,2,1] or [1]), + not ([1,2,..] or [..,2,1] or [1])) => 1, + ([1,2,..] or [1], [..,2,1] or [1]) => 2, + ([..,2,1], [1,2,..]) => 3, + _ => 0 + }; + } + public static int M2(int[] a, int[] b) { + switch (a, b) + { + case (not ([1,2,..] or [..,2,1] or [1]), + not ([1,2,..] or [..,2,1] or [1])): + return 1; + case ([1,2,..] or [1], [..,2,1] or [1]): + return 2; + case ([..,2,1], [1,2,..]): + return 3; + default: + return 0; + } + } +} +"""; + var comp = CreateCompilationWithIndexAndRangeAndSpan(source, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: @" +2 +2 +3 +1 +2 +2 +3 +1 +"); + } + [Fact] public void ListPattern_UseSiteErrorOnIndexerAndSlice() { diff --git a/src/Compilers/CSharp/Test/EndToEnd/EndToEndTests.cs b/src/Compilers/CSharp/Test/EndToEnd/EndToEndTests.cs index b31db4bd27c75..15446d280c917 100644 --- a/src/Compilers/CSharp/Test/EndToEnd/EndToEndTests.cs +++ b/src/Compilers/CSharp/Test/EndToEnd/EndToEndTests.cs @@ -98,7 +98,7 @@ bool runTestAndCatch(int depth) // This test is a canary attempting to make sure that we don't regress the # of fluent calls that // the compiler can handle. [WorkItem(16669, "https://github.com/dotnet/roslyn/issues/16669")] - [ConditionalFact(typeof(WindowsOrLinuxOnly), typeof(IsNot32BitDebug), Reason = "https://github.com/dotnet/roslyn/issues/65940"), WorkItem(34880, "https://github.com/dotnet/roslyn/issues/34880")] + [ConditionalFact(typeof(WindowsOrLinuxOnly)), WorkItem(34880, "https://github.com/dotnet/roslyn/issues/34880")] public void OverflowOnFluentCall() { int numberFluentCalls = (IntPtr.Size, ExecutionConditionUtil.Configuration) switch diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/ConstantTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/ConstantTests.cs index 412a51baa9bb5..36da7e6d98426 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/ConstantTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/ConstantTests.cs @@ -1454,8 +1454,8 @@ private static string ParseAndGetConstantFoldingSteps(string source, Func(). - Where(node => node.ConstantValue != null). - Select(node => node.Syntax.ToFullString().Trim() + " --> " + ExtractValue(node.ConstantValue)); + Where(node => node.ConstantValueOpt != null). + Select(node => node.Syntax.ToFullString().Trim() + " --> " + ExtractValue(node.ConstantValueOpt)); var result = string.Join(Environment.NewLine, constants); return result; } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs index 09ccd0a6ec5b6..43f066abf8992 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs @@ -10766,6 +10766,278 @@ .maxstack 8 CompileAndVerify(comp, expectedOutput: "System.Action`2[System.Int32[],System.Int32]"); } + [ConditionalFact(typeof(CoreClrOnly))] + [WorkItem(63565, "https://github.com/dotnet/roslyn/issues/63565")] + public void SynthesizedDelegateTypes_UnscopedRefAttribute_01() + { + string source = """ + using System; + using System.Diagnostics.CodeAnalysis; + class Program + { + static ref int F(ref int x, [UnscopedRef] ref int y) => ref x; + static void Main() + { + var d = F; + Report(d); + } + static void Report(Delegate d) => Console.WriteLine(d.GetType()); + } + """; + var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net70, verify: Verification.Skipped, expectedOutput: + """ + <>f__AnonymousDelegate0 + """); + verifier.VerifyTypeIL("<>f__AnonymousDelegate0", + """ + .class private auto ansi sealed '<>f__AnonymousDelegate0' + extends [System.Runtime]System.MulticastDelegate + { + .custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor ( + object 'object', + native int 'method' + ) runtime managed + { + } // end of method '<>f__AnonymousDelegate0'::.ctor + .method public hidebysig newslot virtual + instance int32& Invoke ( + int32& arg1, + int32& arg2 + ) runtime managed + { + .param [2] + .custom instance void [System.Runtime]System.Diagnostics.CodeAnalysis.UnscopedRefAttribute::.ctor() = ( + 01 00 00 00 + ) + } // end of method '<>f__AnonymousDelegate0'::Invoke + } // end of class <>f__AnonymousDelegate0 + """); + } + + [ConditionalFact(typeof(CoreClrOnly))] + [WorkItem(63565, "https://github.com/dotnet/roslyn/issues/63565")] + public void SynthesizedDelegateTypes_UnscopedRefAttribute_02() + { + string source = """ + using System; + using System.Diagnostics.CodeAnalysis; + class Program + { + static void Main() + { + var d = ([UnscopedRef] ref int x, ref int y) => ref x; + Report(d); + } + static void Report(Delegate d) => Console.WriteLine(d.GetType()); + } + """; + var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net70, verify: Verification.Skipped, expectedOutput: + """ + <>f__AnonymousDelegate0 + """); + verifier.VerifyTypeIL("<>f__AnonymousDelegate0", + """ + .class private auto ansi sealed '<>f__AnonymousDelegate0' + extends [System.Runtime]System.MulticastDelegate + { + .custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor ( + object 'object', + native int 'method' + ) runtime managed + { + } // end of method '<>f__AnonymousDelegate0'::.ctor + .method public hidebysig newslot virtual + instance int32& Invoke ( + int32& arg1, + int32& arg2 + ) runtime managed + { + .param [1] + .custom instance void [System.Runtime]System.Diagnostics.CodeAnalysis.UnscopedRefAttribute::.ctor() = ( + 01 00 00 00 + ) + } // end of method '<>f__AnonymousDelegate0'::Invoke + } // end of class <>f__AnonymousDelegate0 + """); + } + + [ConditionalFact(typeof(CoreClrOnly))] + [WorkItem(63565, "https://github.com/dotnet/roslyn/issues/63565")] + public void SynthesizedDelegateTypes_UnscopedRefAttribute_03() + { + string source = """ + using System; + using System.Diagnostics.CodeAnalysis; + class Program + { + static ref int F1(ref int x, ref int y) => ref x; + static ref int F2(ref int x, [UnscopedRef] ref int y) => ref x; + static ref int F3([UnscopedRef] ref int x, ref int y) => ref x; + static void Main() + { + var d1 = F1; + var d2 = F2; + var d3 = F3; + var d4 = ([UnscopedRef] ref int x, ref int y) => ref x; + var d5 = (ref int x, [UnscopedRef] ref int y) => ref x; + var d6 = (ref int x, ref int y) => ref x; + Report(d1); + Report(d2); + Report(d3); + Report(d4); + Report(d5); + Report(d6); + } + static void Report(Delegate d) => Console.WriteLine(d.GetType()); + } + """; + var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net70, verify: Verification.Skipped, expectedOutput: + """ + <>F{00000015}`3[System.Int32,System.Int32,System.Int32] + <>f__AnonymousDelegate0 + <>f__AnonymousDelegate1 + <>f__AnonymousDelegate1 + <>f__AnonymousDelegate0 + <>F{00000015}`3[System.Int32,System.Int32,System.Int32] + """); + } + + [ConditionalFact(typeof(CoreClrOnly))] + [WorkItem(63565, "https://github.com/dotnet/roslyn/issues/63565")] + public void SynthesizedDelegateTypes_UnscopedRefAttribute_MissingType() + { + var attributeAssemblyName = GetUniqueName(); + var comp = CreateCompilation(UnscopedRefAttributeDefinition, targetFramework: TargetFramework.Net60, assemblyName: attributeAssemblyName); + var refAttribute = comp.EmitToImageReference(); + + string sourceA = """ + using System.Diagnostics.CodeAnalysis; + public class A + { + public static ref int F([UnscopedRef] ref int i) => ref i; + } + """; + + comp = CreateCompilation(sourceA, references: new[] { refAttribute }, targetFramework: TargetFramework.Net60); + var refA = comp.EmitToImageReference(); + + string sourceB = """ + class Program + { + static void Main() + { + int i = 0; + var d = A.F; + d(ref i); + } + } + """; + + comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net60); + 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)); + + comp = CreateCompilation(sourceB, references: new[] { refA, refAttribute }, targetFramework: TargetFramework.Net60); + var verifier = CompileAndVerify(comp, verify: Verification.Skipped); + verifier.VerifyTypeIL("<>f__AnonymousDelegate0", + $$""" + .class private auto ansi sealed '<>f__AnonymousDelegate0' + extends [System.Runtime]System.MulticastDelegate + { + .custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor ( + object 'object', + native int 'method' + ) runtime managed + { + } // end of method '<>f__AnonymousDelegate0'::.ctor + .method public hidebysig newslot virtual + instance int32& Invoke ( + int32& arg + ) runtime managed + { + .param [1] + .custom instance void ['{{attributeAssemblyName}}']System.Diagnostics.CodeAnalysis.UnscopedRefAttribute::.ctor() = ( + 01 00 00 00 + ) + } // end of method '<>f__AnonymousDelegate0'::Invoke + } // end of class <>f__AnonymousDelegate0 + """); + } + + [ConditionalFact(typeof(CoreClrOnly))] + [WorkItem(63565, "https://github.com/dotnet/roslyn/issues/63565")] + public void SynthesizedDelegateTypes_UnscopedRefAttribute_MissingConstructor_01() + { + 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: new[] { refA }, targetFramework: TargetFramework.Net70); + 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)); + } + + [ConditionalFact(typeof(CoreClrOnly))] + [WorkItem(63565, "https://github.com/dotnet/roslyn/issues/63565")] + public void SynthesizedDelegateTypes_UnscopedRefAttribute_MissingConstructor_02() + { + string source = """ + using System; + using System.Diagnostics.CodeAnalysis; + class Program + { + static void Main() + { + var d = (ref int x, [UnscopedRef] ref int y) => ref y; + Console.WriteLine(d); + } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.MakeMemberMissing(WellKnownMember.System_Diagnostics_CodeAnalysis_UnscopedRefAttribute__ctor); + comp.VerifyEmitDiagnostics( + // (7,51): error CS0656: Missing compiler required member 'System.Diagnostics.CodeAnalysis.UnscopedRefAttribute..ctor' + // var d = (ref int x, [UnscopedRef] ref int y) => ref y; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "y").WithArguments("System.Diagnostics.CodeAnalysis.UnscopedRefAttribute", ".ctor").WithLocation(7, 51)); + } + private static void VerifyLocalDelegateType(SemanticModel model, VariableDeclaratorSyntax variable, string expectedInvokeMethod) { var expectedBaseType = ((CSharpCompilation)model.Compilation).GetSpecialType(SpecialType.System_MulticastDelegate); @@ -14225,89 +14497,1312 @@ public static void Main() 5").VerifyDiagnostics(); } - [Fact] - public void LambdaDefaultParameter_ArrayCommonType_DefaultValueMismatch() + // delegate void <>f__AnonymousDelegate0([Optional, DecimalConstant(1, 0, 0u, 0u, 11u)] T1 d) + // (the decimal constant is equivalent to 1.1m) + private static readonly string s_anonymousDelegateWithDecimalConstant = $$""" + .class private auto ansi sealed '<>f__AnonymousDelegate0`1' + extends [{{s_libPrefix}}]System.MulticastDelegate + { + .custom instance void [{{s_libPrefix}}]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor ( + object 'object', + native int 'method' + ) runtime managed + { + } // end of method '<>f__AnonymousDelegate0`1'::.ctor + .method public hidebysig newslot virtual + instance void Invoke ( + [opt] !T1 arg + ) runtime managed + { + .param [1] + .custom instance void [{{s_libPrefix}}]System.Runtime.CompilerServices.DecimalConstantAttribute::.ctor(uint8, uint8, uint32, uint32, uint32) = ( + 01 00 01 00 00 00 00 00 00 00 00 00 0b 00 00 00 + 00 00 + ) + } // end of method '<>f__AnonymousDelegate0`1'::Invoke + } // end of class <>f__AnonymousDelegate0`1 + """; + + [Fact, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + public void DefaultParameterValue_Decimal_Lambda_DelegateIL() { var source = """ - var arr = new[] { (int i = 1) => { }, (int i = 2) => { } }; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + static void Report(object obj) => System.Console.WriteLine(obj.GetType()); + + var lam1 = (decimal d = 1.1m) => {}; + Report(lam1); + var lam2 = ([Optional, DecimalConstant(1, 0, 0u, 0u, 11u)] decimal d) => {}; + Report(lam2); + var lam3 = ([DecimalConstant(1, 0, 0u, 0u, 11u)] decimal d = 1.1m) => {}; + Report(lam3); + var lam4 = ([DecimalConstant(1, 0, 0u, 0u, 11u)] decimal d) => {}; + Report(lam4); + var lam5 = (decimal? d = 1.1m) => {}; + Report(lam5); + var lam6 = ([Optional, DecimalConstant(1, 0, 0u, 0u, 11u)] decimal? d) => {}; + Report(lam6); + var lam7 = ([DecimalConstant(1, 0, 0u, 0u, 11u)] decimal? d = 1.1m) => {}; + Report(lam7); + var lam8 = ([DecimalConstant(1, 0, 0u, 0u, 11u)] decimal? d) => {}; + Report(lam8); """; - CreateCompilation(source).VerifyDiagnostics( - // (1,11): error CS0826: No best type found for implicitly-typed array - // var arr = new[] { (int i = 1) => { }, (int i = 2) => { } }; - Diagnostic(ErrorCode.ERR_ImplicitlyTypedArrayNoBestType, "new[] { (int i = 1) => { }, (int i = 2) => { } }").WithLocation(1, 11)); + var verifier = CompileAndVerify(source, expectedOutput: """ + <>f__AnonymousDelegate0`1[System.Decimal] + <>f__AnonymousDelegate0`1[System.Decimal] + <>f__AnonymousDelegate0`1[System.Decimal] + System.Action`1[System.Decimal] + <>f__AnonymousDelegate0`1[System.Nullable`1[System.Decimal]] + <>f__AnonymousDelegate0`1[System.Nullable`1[System.Decimal]] + <>f__AnonymousDelegate0`1[System.Nullable`1[System.Decimal]] + System.Action`1[System.Nullable`1[System.Decimal]] + """).VerifyDiagnostics(); + verifier.VerifyTypeIL("<>f__AnonymousDelegate0`1", s_anonymousDelegateWithDecimalConstant); } - [Fact] - public void LambdaDefaultParameter_ArrayCommonType_DefaultValueMatch() + [Fact, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + public void DefaultParameterValue_Decimal_Lambda_ClosureIL() { var source = """ -using System; -class Program -{ - static void Report(object obj) => Console.WriteLine(obj.GetType()); - public static void Main() - { - var arr = new[] { (int i = 1) => { }, (int i = 1) => { } }; - Report(arr); - } -} -"""; - CompileAndVerify(source, expectedOutput: -@"<>f__AnonymousDelegate0`1[System.Int32][]").VerifyDiagnostics(); + var lam1 = (decimal d = 1.1m) => {}; + var lam2 = (decimal? d = 1.1m) => {}; + """; + var verifier = CompileAndVerify(source).VerifyDiagnostics(); + verifier.VerifyTypeIL("<>c", $$""" + .class nested private auto ansi sealed serializable beforefieldinit '<>c' + extends [{{s_libPrefix}}]System.Object + { + .custom instance void [{{s_libPrefix}}]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Fields + .field public static initonly class Program/'<>c' '<>9' + .field public static class '<>f__AnonymousDelegate0`1' '<>9__0_0' + .field public static class '<>f__AnonymousDelegate0`1'> '<>9__0_1' + // Methods + .method private hidebysig specialname rtspecialname static + void .cctor () cil managed + { + // Method begins at RVA 0x20a9 + // Code size 11 (0xb) + .maxstack 8 + IL_0000: newobj instance void Program/'<>c'::.ctor() + IL_0005: stsfld class Program/'<>c' Program/'<>c'::'<>9' + IL_000a: ret + } // end of method '<>c'::.cctor + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + // Method begins at RVA 0x20a1 + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [{{s_libPrefix}}]System.Object::.ctor() + IL_0006: ret + } // end of method '<>c'::.ctor + .method assembly hidebysig + instance void '<
$>b__0_0' ( + [opt] valuetype [{{s_libPrefix}}]System.Decimal d + ) cil managed + { + .param [1] + .custom instance void [{{s_libPrefix}}]System.Runtime.CompilerServices.DecimalConstantAttribute::.ctor(uint8, uint8, uint32, uint32, uint32) = ( + 01 00 01 00 00 00 00 00 00 00 00 00 0b 00 00 00 + 00 00 + ) + // Method begins at RVA 0x20b5 + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>c'::'<
$>b__0_0' + .method assembly hidebysig + instance void '<
$>b__0_1' ( + [opt] valuetype [{{s_libPrefix}}]System.Nullable`1 d + ) cil managed + { + .param [1] + .custom instance void [{{s_libPrefix}}]System.Runtime.CompilerServices.DecimalConstantAttribute::.ctor(uint8, uint8, uint32, uint32, uint32) = ( + 01 00 01 00 00 00 00 00 00 00 00 00 0b 00 00 00 + 00 00 + ) + // Method begins at RVA 0x20b5 + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>c'::'<
$>b__0_1' + } // end of class <>c + """); } - [Fact] - public void LambdaDefaultParameter_InsideExpressionTree() + [Fact, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + public void DefaultParameterValue_Decimal_LocalFunction_DelegateIL() { var source = """ -using System; -using System.Linq.Expressions; -class Program -{ - static void Report(object obj) => Console.WriteLine(obj.GetType()); - public static void Main() - { - Expression e1 = (int x = 1) => x; - Expression e2 = (int x) => (int y = 1) => y; - Report(e1); - Report(e2); - } -} -"""; - CompileAndVerify(source, expectedOutput: -$@"{s_expressionOfTDelegate1ArgTypeName}[<>f__AnonymousDelegate0`2[System.Int32,System.Int32]] -{s_expressionOfTDelegate1ArgTypeName}[System.Func`2[System.Int32,<>f__AnonymousDelegate0`2[System.Int32,System.Int32]]]").VerifyDiagnostics(); + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + static void Report(System.Delegate obj) => System.Console.WriteLine(obj.GetType()); + + void local1(decimal d = 1.1m) {} + Report(local1); + void local2([Optional, DecimalConstant(1, 0, 0u, 0u, 11u)] decimal d) {} + Report(local2); + void local3([DecimalConstant(1, 0, 0u, 0u, 11u)] decimal d = 1.1m) {} + Report(local3); + void local4([DecimalConstant(1, 0, 0u, 0u, 11u)] decimal d) {} + Report(local4); + void local5(decimal? d = 1.1m) {} + Report(local5); + void local6([Optional, DecimalConstant(1, 0, 0u, 0u, 11u)] decimal? d) {} + Report(local6); + void local7([DecimalConstant(1, 0, 0u, 0u, 11u)] decimal? d = 1.1m) {} + Report(local7); + void local8([DecimalConstant(1, 0, 0u, 0u, 11u)] decimal? d) {} + Report(local8); + """; + var verifier = CompileAndVerify(source, expectedOutput: """ + <>f__AnonymousDelegate0`1[System.Decimal] + <>f__AnonymousDelegate0`1[System.Decimal] + <>f__AnonymousDelegate0`1[System.Decimal] + System.Action`1[System.Decimal] + <>f__AnonymousDelegate0`1[System.Nullable`1[System.Decimal]] + <>f__AnonymousDelegate0`1[System.Nullable`1[System.Decimal]] + <>f__AnonymousDelegate0`1[System.Nullable`1[System.Decimal]] + System.Action`1[System.Nullable`1[System.Decimal]] + """).VerifyDiagnostics(); + verifier.VerifyTypeIL("<>f__AnonymousDelegate0`1", s_anonymousDelegateWithDecimalConstant); } - [Fact] - public void LambdaDefaultParameter_MissingConstantValueType() + [Fact, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + public void DefaultParameterValue_Decimal_LocalFunction_ClosureIL() { var source = """ - var lam1 = (object f = 1.0) => f; - var lam2 = (object d = 2m) => d; - namespace System - { - public class Object { } - public class String { } - public abstract class ValueType { } - public struct Void { } - public abstract class Delegate { } - public abstract class MulticastDelegate : Delegate { } - } + #pragma warning disable CS8321 // The local function is declared but never used + + void local1(decimal d = 1.1m) {} + void local2(decimal? d = 1.1m) {} """; - CreateEmptyCompilation(source).VerifyDiagnostics( - // (1,20): error CS1763: 'f' is of type 'object'. A default parameter value of a reference type other than string can only be initialized with null - // var lam1 = (object f = 1.0) => f; - Diagnostic(ErrorCode.ERR_NotNullRefDefaultParameter, "f").WithArguments("f", "object").WithLocation(1, 20), - // (1,24): error CS0518: Predefined type 'System.Double' is not defined or imported - // var lam1 = (object f = 1.0) => f; - Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "1.0").WithArguments("System.Double").WithLocation(1, 24), - // (2,20): error CS1763: 'd' is of type 'object'. A default parameter value of a reference type other than string can only be initialized with null - // var lam2 = (object d = 2m) => d; - Diagnostic(ErrorCode.ERR_NotNullRefDefaultParameter, "d").WithArguments("d", "object").WithLocation(2, 20), - // (2,24): error CS0518: Predefined type 'System.Decimal' is not defined or imported - // var lam2 = (object d = 2m) => d; - Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "2m").WithArguments("System.Decimal").WithLocation(2, 24)); + var verifier = CompileAndVerify(source).VerifyDiagnostics(); + verifier.VerifyTypeIL("Program", $$""" + .class private auto ansi beforefieldinit Program + extends [{{s_libPrefix}}]System.Object + { + .custom instance void [{{s_libPrefix}}]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Methods + .method private hidebysig static + void '
$' ( + string[] args + ) cil managed + { + // Method begins at RVA 0x2067 + // Code size 1 (0x1) + .maxstack 8 + .entrypoint + IL_0000: ret + } // end of method Program::'
$' + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + // Method begins at RVA 0x2069 + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [{{s_libPrefix}}]System.Object::.ctor() + IL_0006: ret + } // end of method Program::.ctor + .method assembly hidebysig static + void '<
$>g__local1|0_0' ( + [opt] valuetype [{{s_libPrefix}}]System.Decimal d + ) cil managed + { + .custom instance void [{{s_libPrefix}}]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + .param [1] + .custom instance void [{{s_libPrefix}}]System.Runtime.CompilerServices.DecimalConstantAttribute::.ctor(uint8, uint8, uint32, uint32, uint32) = ( + 01 00 01 00 00 00 00 00 00 00 00 00 0b 00 00 00 + 00 00 + ) + // Method begins at RVA 0x2067 + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method Program::'<
$>g__local1|0_0' + .method assembly hidebysig static + void '<
$>g__local2|0_1' ( + [opt] valuetype [{{s_libPrefix}}]System.Nullable`1 d + ) cil managed + { + .custom instance void [{{s_libPrefix}}]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + .param [1] + .custom instance void [{{s_libPrefix}}]System.Runtime.CompilerServices.DecimalConstantAttribute::.ctor(uint8, uint8, uint32, uint32, uint32) = ( + 01 00 01 00 00 00 00 00 00 00 00 00 0b 00 00 00 + 00 00 + ) + // Method begins at RVA 0x2067 + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method Program::'<
$>g__local2|0_1' + } // end of class Program + """); + } + + [Fact, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + public void DefaultParameterValue_Decimal_MethodGroup() + { + var source = """ + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + static void Report(object obj) => System.Console.WriteLine(obj.GetType()); + + var m1 = C.M1; + Report(m1); + var m2 = C.M2; + Report(m2); + var m3 = C.M3; + Report(m3); + var m4 = C.M4; + Report(m4); + var m5 = C.M5; + Report(m5); + var m6 = C.M6; + Report(m6); + var m7 = C.M7; + Report(m7); + var m8 = C.M8; + Report(m8); + + class C + { + public static void M1(decimal d = 1.1m) {} + public static void M2([Optional, DecimalConstant(1, 0, 0u, 0u, 11u)] decimal d) {} + public static void M3([DecimalConstant(1, 0, 0u, 0u, 11u)] decimal d = 1.1m) {} + public static void M4([DecimalConstant(1, 0, 0u, 0u, 11u)] decimal d) {} + public static void M5(decimal? d = 1.1m) {} + public static void M6([Optional, DecimalConstant(1, 0, 0u, 0u, 11u)] decimal? d) {} + public static void M7([DecimalConstant(1, 0, 0u, 0u, 11u)] decimal? d = 1.1m) {} + public static void M8([DecimalConstant(1, 0, 0u, 0u, 11u)] decimal? d) {} + } + """; + var verifier = CompileAndVerify(source, expectedOutput: """ + <>f__AnonymousDelegate0`1[System.Decimal] + <>f__AnonymousDelegate0`1[System.Decimal] + <>f__AnonymousDelegate0`1[System.Decimal] + System.Action`1[System.Decimal] + <>f__AnonymousDelegate0`1[System.Nullable`1[System.Decimal]] + <>f__AnonymousDelegate0`1[System.Nullable`1[System.Decimal]] + <>f__AnonymousDelegate0`1[System.Nullable`1[System.Decimal]] + System.Action`1[System.Nullable`1[System.Decimal]] + """).VerifyDiagnostics(); + verifier.VerifyTypeIL("<>f__AnonymousDelegate0`1", s_anonymousDelegateWithDecimalConstant); + } + + // delegate void <>f__AnonymousDelegate0([Optional, DateTimeConstant(100L)] T1 d) + private static readonly string s_anonymousDelegateWithDateTimeConstant = $$""" + .class private auto ansi sealed '<>f__AnonymousDelegate0`1' + extends [{{s_libPrefix}}]System.MulticastDelegate + { + .custom instance void [{{s_libPrefix}}]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor ( + object 'object', + native int 'method' + ) runtime managed + { + } // end of method '<>f__AnonymousDelegate0`1'::.ctor + .method public hidebysig newslot virtual + instance void Invoke ( + [opt] !T1 arg + ) runtime managed + { + .param [1] + .custom instance void [{{s_libPrefix}}]System.Runtime.CompilerServices.DateTimeConstantAttribute::.ctor(int64) = ( + 01 00 64 00 00 00 00 00 00 00 00 00 + ) + } // end of method '<>f__AnonymousDelegate0`1'::Invoke + } // end of class <>f__AnonymousDelegate0`1 + """; + + [Fact, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + public void DefaultParameterValue_DateTime_Lambda_DelegateIL() + { + var source = """ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + static void Report(object obj) => System.Console.WriteLine(obj.GetType()); + + var lam1 = ([Optional, DateTimeConstant(100L)] DateTime d) => {}; + Report(lam1); + var lam2 = ([Optional, DateTimeConstant(100L)] DateTime? d) => {}; + Report(lam2); + var lam3 = ([DateTimeConstant(100L)] DateTime d) => {}; + Report(lam3); + """; + var verifier = CompileAndVerify(source, expectedOutput: """ + <>f__AnonymousDelegate0`1[System.DateTime] + <>f__AnonymousDelegate0`1[System.Nullable`1[System.DateTime]] + System.Action`1[System.DateTime] + """).VerifyDiagnostics(); + verifier.VerifyTypeIL("<>f__AnonymousDelegate0`1", s_anonymousDelegateWithDateTimeConstant); + } + + [Fact, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + public void DefaultParameterValue_DateTime_Lambda_ClosureIL() + { + var source = """ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + var lam1 = ([Optional, DateTimeConstant(100L)] DateTime d) => {}; + var lam2 = ([Optional, DateTimeConstant(100L)] DateTime? d) => {}; + """; + var verifier = CompileAndVerify(source).VerifyDiagnostics(); + verifier.VerifyTypeIL("<>c", $$""" + .class nested private auto ansi sealed serializable beforefieldinit '<>c' + extends [{{s_libPrefix}}]System.Object + { + .custom instance void [{{s_libPrefix}}]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Fields + .field public static initonly class Program/'<>c' '<>9' + .field public static class '<>f__AnonymousDelegate0`1' '<>9__0_0' + .field public static class '<>f__AnonymousDelegate0`1'> '<>9__0_1' + // Methods + .method private hidebysig specialname rtspecialname static + void .cctor () cil managed + { + // Method begins at RVA 0x20a9 + // Code size 11 (0xb) + .maxstack 8 + IL_0000: newobj instance void Program/'<>c'::.ctor() + IL_0005: stsfld class Program/'<>c' Program/'<>c'::'<>9' + IL_000a: ret + } // end of method '<>c'::.cctor + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + // Method begins at RVA 0x20a1 + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [{{s_libPrefix}}]System.Object::.ctor() + IL_0006: ret + } // end of method '<>c'::.ctor + .method assembly hidebysig + instance void '<
$>b__0_0' ( + [opt] valuetype [{{s_libPrefix}}]System.DateTime d + ) cil managed + { + .param [1] + .custom instance void [{{s_libPrefix}}]System.Runtime.CompilerServices.DateTimeConstantAttribute::.ctor(int64) = ( + 01 00 64 00 00 00 00 00 00 00 00 00 + ) + // Method begins at RVA 0x20b5 + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>c'::'<
$>b__0_0' + .method assembly hidebysig + instance void '<
$>b__0_1' ( + [opt] valuetype [{{s_libPrefix}}]System.Nullable`1 d + ) cil managed + { + .param [1] + .custom instance void [{{s_libPrefix}}]System.Runtime.CompilerServices.DateTimeConstantAttribute::.ctor(int64) = ( + 01 00 64 00 00 00 00 00 00 00 00 00 + ) + // Method begins at RVA 0x20b5 + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '<>c'::'<
$>b__0_1' + } // end of class <>c + """); + } + + [Fact, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + public void DefaultParameterValue_DateTime_LocalFunction_DelegateIL() + { + var source = """ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + static void Report(Delegate obj) => System.Console.WriteLine(obj.GetType()); + + void local1([Optional, DateTimeConstant(100L)] DateTime d) {} + Report(local1); + void local2([Optional, DateTimeConstant(100L)] DateTime? d) {} + Report(local2); + void local3([DateTimeConstant(100L)] DateTime d) {} + Report(local3); + """; + var verifier = CompileAndVerify(source, expectedOutput: """ + <>f__AnonymousDelegate0`1[System.DateTime] + <>f__AnonymousDelegate0`1[System.Nullable`1[System.DateTime]] + System.Action`1[System.DateTime] + """).VerifyDiagnostics(); + verifier.VerifyTypeIL("<>f__AnonymousDelegate0`1", s_anonymousDelegateWithDateTimeConstant); + } + + [Fact, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + public void DefaultParameterValue_DateTime_LocalFunction_ClosureIL() + { + var source = """ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + #pragma warning disable CS8321 // The local function is declared but never used + + void local1([Optional, DateTimeConstant(100L)] DateTime d) {} + void local2([Optional, DateTimeConstant(100L)] DateTime? d) {} + """; + var verifier = CompileAndVerify(source).VerifyDiagnostics(); + verifier.VerifyTypeIL("Program", $$""" + .class private auto ansi beforefieldinit Program + extends [{{s_libPrefix}}]System.Object + { + .custom instance void [{{s_libPrefix}}]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Methods + .method private hidebysig static + void '
$' ( + string[] args + ) cil managed + { + // Method begins at RVA 0x2067 + // Code size 1 (0x1) + .maxstack 8 + .entrypoint + IL_0000: ret + } // end of method Program::'
$' + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + // Method begins at RVA 0x2069 + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [{{s_libPrefix}}]System.Object::.ctor() + IL_0006: ret + } // end of method Program::.ctor + .method assembly hidebysig static + void '<
$>g__local1|0_0' ( + [opt] valuetype [{{s_libPrefix}}]System.DateTime d + ) cil managed + { + .custom instance void [{{s_libPrefix}}]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + .param [1] + .custom instance void [{{s_libPrefix}}]System.Runtime.CompilerServices.DateTimeConstantAttribute::.ctor(int64) = ( + 01 00 64 00 00 00 00 00 00 00 00 00 + ) + // Method begins at RVA 0x2067 + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method Program::'<
$>g__local1|0_0' + .method assembly hidebysig static + void '<
$>g__local2|0_1' ( + [opt] valuetype [{{s_libPrefix}}]System.Nullable`1 d + ) cil managed + { + .custom instance void [{{s_libPrefix}}]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + .param [1] + .custom instance void [{{s_libPrefix}}]System.Runtime.CompilerServices.DateTimeConstantAttribute::.ctor(int64) = ( + 01 00 64 00 00 00 00 00 00 00 00 00 + ) + // Method begins at RVA 0x2067 + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method Program::'<
$>g__local2|0_1' + } // end of class Program + """); + } + + [Fact, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + public void DefaultParameterValue_DateTime_MethodGroup() + { + var source = """ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + static void Report(object obj) => System.Console.WriteLine(obj.GetType()); + + var m1 = C.M1; + Report(m1); + var m2 = C.M2; + Report(m2); + var m3 = C.M3; + Report(m3); + + public class C + { + public static void M1([Optional, DateTimeConstant(100L)] DateTime d) {} + public static void M2([Optional, DateTimeConstant(100L)] DateTime? d) {} + public static void M3([DateTimeConstant(100L)] DateTime d) {} + } + """; + var verifier = CompileAndVerify(source, expectedOutput: """ + <>f__AnonymousDelegate0`1[System.DateTime] + <>f__AnonymousDelegate0`1[System.Nullable`1[System.DateTime]] + System.Action`1[System.DateTime] + """).VerifyDiagnostics(); + verifier.VerifyTypeIL("<>f__AnonymousDelegate0`1", s_anonymousDelegateWithDateTimeConstant); + } + + [Fact] + public void LambdaDefaultParameter_ArrayCommonType_DefaultValueMismatch() + { + var source = """ + var arr = new[] { (int i = 1) => { }, (int i = 2) => { } }; + """; + CreateCompilation(source).VerifyDiagnostics( + // (1,11): error CS0826: No best type found for implicitly-typed array + // var arr = new[] { (int i = 1) => { }, (int i = 2) => { } }; + Diagnostic(ErrorCode.ERR_ImplicitlyTypedArrayNoBestType, "new[] { (int i = 1) => { }, (int i = 2) => { } }").WithLocation(1, 11)); + } + + [Fact] + public void LambdaDefaultParameter_ArrayCommonType_DefaultValueMatch() + { + var source = """ +using System; +class Program +{ + static void Report(object obj) => Console.WriteLine(obj.GetType()); + public static void Main() + { + var arr = new[] { (int i = 1) => { }, (int i = 1) => { } }; + Report(arr); + } +} +"""; + CompileAndVerify(source, expectedOutput: +@"<>f__AnonymousDelegate0`1[System.Int32][]").VerifyDiagnostics(); + } + + [Fact] + public void LambdaDefaultParameter_InsideExpressionTree() + { + var source = """ +using System; +using System.Linq.Expressions; +class Program +{ + static void Report(object obj) => Console.WriteLine(obj.GetType()); + public static void Main() + { + Expression e1 = (int x = 1) => x; + Expression e2 = (int x) => (int y = 1) => y; + Report(e1); + Report(e2); + } +} +"""; + CompileAndVerify(source, expectedOutput: +$@"{s_expressionOfTDelegate1ArgTypeName}[<>f__AnonymousDelegate0`2[System.Int32,System.Int32]] +{s_expressionOfTDelegate1ArgTypeName}[System.Func`2[System.Int32,<>f__AnonymousDelegate0`2[System.Int32,System.Int32]]]").VerifyDiagnostics(); + } + + [Fact] + public void LambdaDefaultParameter_MissingConstantValueType() + { + var source = """ + var lam1 = (object f = 1.0) => f; + var lam2 = (object d = 2m) => d; + namespace System + { + public class Object { } + public class String { } + public abstract class ValueType { } + public struct Void { } + public abstract class Delegate { } + public abstract class MulticastDelegate : Delegate { } + } + """; + CreateEmptyCompilation(source).VerifyDiagnostics( + // (1,20): error CS1763: 'f' is of type 'object'. A default parameter value of a reference type other than string can only be initialized with null + // var lam1 = (object f = 1.0) => f; + Diagnostic(ErrorCode.ERR_NotNullRefDefaultParameter, "f").WithArguments("f", "object").WithLocation(1, 20), + // (1,24): error CS0518: Predefined type 'System.Double' is not defined or imported + // var lam1 = (object f = 1.0) => f; + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "1.0").WithArguments("System.Double").WithLocation(1, 24), + // (2,20): error CS1763: 'd' is of type 'object'. A default parameter value of a reference type other than string can only be initialized with null + // var lam2 = (object d = 2m) => d; + Diagnostic(ErrorCode.ERR_NotNullRefDefaultParameter, "d").WithArguments("d", "object").WithLocation(2, 20), + // (2,24): error CS0518: Predefined type 'System.Decimal' is not defined or imported + // var lam2 = (object d = 2m) => d; + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "2m").WithArguments("System.Decimal").WithLocation(2, 24)); + } + + [Theory, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + [InlineData("decimal ")] + [InlineData("decimal?")] + public void MissingDecimalConstantAttribute_Lambda(string type) + { + var source = $$""" + var lam = ({{type}} d = 1.1m) => { }; + var lam2 = lam; + """; + + var diagnostics = new[] + { + // (1,25): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.DecimalConstantAttribute..ctor' + // var lam = (decimal d = 1.1m) => { }; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "1.1m").WithArguments("System.Runtime.CompilerServices.DecimalConstantAttribute", ".ctor").WithLocation(1, 25) + }; + + var comp = CreateCompilation(source); + comp.MakeTypeMissing(WellKnownType.System_Runtime_CompilerServices_DecimalConstantAttribute); + comp.VerifyDiagnostics(diagnostics); + + comp = CreateCompilation(source); + comp.MakeMemberMissing(WellKnownMember.System_Runtime_CompilerServices_DecimalConstantAttribute__ctor); + comp.VerifyDiagnostics(diagnostics); + + comp = CreateCompilation(source); + comp.MakeMemberMissing(WellKnownMember.System_Runtime_CompilerServices_DecimalConstantAttribute__ctorByteByteInt32Int32Int32); + comp.VerifyEmitDiagnostics(); + } + + [Theory, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + [InlineData("decimal ")] + [InlineData("decimal?")] + public void MissingDecimalConstantAttribute_Lambda_AsArgument(string type) + { + var source = $$""" + TakeDelegate(({{type}} d = 1.1m) => { }); + + static void TakeDelegate(System.Delegate d) { } + """; + var comp = CreateCompilation(source); + comp.MakeTypeMissing(WellKnownType.System_Runtime_CompilerServices_DecimalConstantAttribute); + comp.VerifyDiagnostics( + // (1,28): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.DecimalConstantAttribute..ctor' + // TakeDelegate((decimal d = 1.1m) => { }); + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "1.1m").WithArguments("System.Runtime.CompilerServices.DecimalConstantAttribute", ".ctor").WithLocation(1, 28)); + } + + [Theory, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + [InlineData("decimal ")] + [InlineData("decimal?")] + public void MissingDecimalConstantAttribute_Lambda_AsGenericArgument(string type) + { + var source = $$""" + TakeDelegate(({{type}} d = 1.1m) => { }); + + static void TakeDelegate(T d) where T : System.Delegate { } + """; + var comp = CreateCompilation(source); + comp.MakeTypeMissing(WellKnownType.System_Runtime_CompilerServices_DecimalConstantAttribute); + comp.VerifyDiagnostics( + // (1,28): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.DecimalConstantAttribute..ctor' + // TakeDelegate((decimal d = 1.1m) => { }); + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "1.1m").WithArguments("System.Runtime.CompilerServices.DecimalConstantAttribute", ".ctor").WithLocation(1, 28)); + } + + [Theory, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + [InlineData("decimal ")] + [InlineData("decimal?")] + public void MissingDecimalConstantAttribute_Lambda_CustomType(string type) + { + var source = $$""" + Del lam = ({{type}} d = 1.1m) => { }; + + delegate void Del({{type}} d = 1.1m); + """; + var comp = CreateCompilation(source); + comp.MakeTypeMissing(WellKnownType.System_Runtime_CompilerServices_DecimalConstantAttribute); + comp.VerifyDiagnostics( + // (1,25): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.DecimalConstantAttribute..ctor' + // Del lam = (decimal d = 1.1m) => { }; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "1.1m").WithArguments("System.Runtime.CompilerServices.DecimalConstantAttribute", ".ctor").WithLocation(1, 25), + // (3,32): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.DecimalConstantAttribute..ctor' + // delegate void Del(decimal d = 1.1m); + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "1.1m").WithArguments("System.Runtime.CompilerServices.DecimalConstantAttribute", ".ctor").WithLocation(3, 32)); + } + + [Theory, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + [InlineData("decimal", "System.Decimal")] + [InlineData("decimal?", "System.Nullable`1[System.Decimal]")] + public void MissingDecimalConstantAttribute_Lambda_ExplicitAttribute_Alone(string type, string typeFullName) + { + var source = $$""" + using System.Runtime.CompilerServices; + + var lam = ([DecimalConstant(1, 0, 0u, 0u, 11u)] {{type}} d) => { }; + System.Console.WriteLine(lam.GetType()); + var lam2 = lam; + System.Console.WriteLine(lam2.GetType()); + """; + var comp = CreateCompilation(source); + comp.MakeTypeMissing(WellKnownType.System_Runtime_CompilerServices_DecimalConstantAttribute); + CompileAndVerify(comp, expectedOutput: $""" + System.Action`1[{typeFullName}] + System.Action`1[{typeFullName}] + """).VerifyDiagnostics(); + } + + [Theory, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + [InlineData("decimal")] + [InlineData("decimal?")] + public void MissingDecimalConstantAttribute_Lambda_ExplicitAttribute_Alone_CustomType(string type) + { + var source = $$""" + using System.Runtime.CompilerServices; + + Del lam = ([DecimalConstant(1, 0, 0u, 0u, 11u)] {{type}} d) => { }; + + delegate void Del([DecimalConstant(1, 0, 0u, 0u, 11u)] {{type}} d); + """; + var comp = CreateCompilation(source); + comp.MakeTypeMissing(WellKnownType.System_Runtime_CompilerServices_DecimalConstantAttribute); + comp.VerifyEmitDiagnostics(); + } + + [Theory, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + [InlineData("decimal ")] + [InlineData("decimal?")] + public void MissingDecimalConstantAttribute_Lambda_ExplicitAttribute_WithOptional(string type) + { + var source = $$""" + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + var lam = ([Optional, DecimalConstant(1, 0, 0u, 0u, 11u)] {{type}} d) => { }; + var lam2 = lam; + """; + var comp = CreateCompilation(source); + comp.MakeTypeMissing(WellKnownType.System_Runtime_CompilerServices_DecimalConstantAttribute); + comp.VerifyDiagnostics( + // (4,68): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.DecimalConstantAttribute..ctor' + // var lam = ([Optional, DecimalConstant(1, 0, 0u, 0u, 11u)] decimal d) => { }; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "d").WithArguments("System.Runtime.CompilerServices.DecimalConstantAttribute", ".ctor").WithLocation(4, 68)); + } + + [Theory, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + [InlineData("decimal ")] + [InlineData("decimal?")] + public void MissingDecimalConstantAttribute_Lambda_ExplicitAttribute_WithOptional_CustomType(string type) + { + var source = $$""" + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + Del lam = ([Optional, DecimalConstant(1, 0, 0u, 0u, 11u)] {{type}} d) => { }; + + delegate void Del([Optional, DecimalConstant(1, 0, 0u, 0u, 11u)] {{type}} d); + """; + var comp = CreateCompilation(source); + comp.MakeTypeMissing(WellKnownType.System_Runtime_CompilerServices_DecimalConstantAttribute); + comp.VerifyEmitDiagnostics(); + } + + [Theory, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + [InlineData("decimal ")] + [InlineData("decimal?")] + public void MissingDecimalConstantAttribute_Lambda_ExplicitAttribute_WithDefault(string type) + { + var source = $$""" + using System.Runtime.CompilerServices; + + var lam = ([DecimalConstant(1, 0, 0u, 0u, 11u)] {{type}} d = 1.1m) => { }; + var lam2 = lam; + """; + var comp = CreateCompilation(source); + comp.MakeTypeMissing(WellKnownType.System_Runtime_CompilerServices_DecimalConstantAttribute); + comp.VerifyDiagnostics( + // (3,58): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.DecimalConstantAttribute..ctor' + // var lam = ([DecimalConstant(1, 0, 0u, 0u, 11u)] decimal d = 1.1m) => { }; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "d").WithArguments("System.Runtime.CompilerServices.DecimalConstantAttribute", ".ctor").WithLocation(3, 58)); + } + + [Theory, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + [InlineData("decimal ")] + [InlineData("decimal?")] + public void MissingDecimalConstantAttribute_Lambda_ExplicitAttribute_WithDefault_CustomType(string type) + { + var source = $$""" + using System.Runtime.CompilerServices; + + Del lam = ([DecimalConstant(1, 0, 0u, 0u, 11u)] {{type}} d = 1.1m) => { }; + + delegate void Del([DecimalConstant(1, 0, 0u, 0u, 11u)] {{type}} d = 1.1m); + """; + var comp = CreateCompilation(source); + comp.MakeTypeMissing(WellKnownType.System_Runtime_CompilerServices_DecimalConstantAttribute); + comp.VerifyEmitDiagnostics(); + } + + [Theory, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + [InlineData("decimal ")] + [InlineData("decimal?")] + public void MissingDecimalConstantAttribute_Method(string type) + { + var source = $$""" + var m = C.M; + + class C + { + public static void M({{type}} d = 1.1m) { } + } + """; + var comp = CreateCompilation(source); + comp.MakeTypeMissing(WellKnownType.System_Runtime_CompilerServices_DecimalConstantAttribute); + comp.VerifyDiagnostics( + // (1,9): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.DecimalConstantAttribute..ctor' + // var m = C.M; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "C.M").WithArguments("System.Runtime.CompilerServices.DecimalConstantAttribute", ".ctor").WithLocation(1, 9), + // (5,39): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.DecimalConstantAttribute..ctor' + // public static void M(decimal d = 1.1m) { } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "1.1m").WithArguments("System.Runtime.CompilerServices.DecimalConstantAttribute", ".ctor").WithLocation(5, 39)); + } + + [Theory, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + [InlineData("decimal ")] + [InlineData("decimal?")] + public void MissingDecimalConstantAttribute_Method_ExplicitAttribute_WithOptional(string type) + { + var source = $$""" + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + var m = C.M; + + class C + { + public static void M([Optional, DecimalConstant(1, 0, 0u, 0u, 11u)] {{type}} d) { } + } + """; + var comp = CreateCompilation(source); + comp.MakeTypeMissing(WellKnownType.System_Runtime_CompilerServices_DecimalConstantAttribute); + comp.VerifyDiagnostics( + // (4,9): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.DecimalConstantAttribute..ctor' + // var m = C.M; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "C.M").WithArguments("System.Runtime.CompilerServices.DecimalConstantAttribute", ".ctor").WithLocation(4, 9)); + } + + [Theory, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + [InlineData("decimal ")] + [InlineData("decimal?")] + public void MissingDecimalConstantAttribute_Method_ExplicitAttribute_WithOptional_CustomType(string type) + { + var source = $$""" + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + Del m = C.M; + + class C + { + public static void M([Optional, DecimalConstant(1, 0, 0u, 0u, 11u)] {{type}} d) { } + } + + delegate void Del([Optional, DecimalConstant(1, 0, 0u, 0u, 11u)] {{type}} d); + """; + var comp = CreateCompilation(source); + comp.MakeTypeMissing(WellKnownType.System_Runtime_CompilerServices_DecimalConstantAttribute); + comp.VerifyEmitDiagnostics(); + } + + [Theory, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + [InlineData("decimal ")] + [InlineData("decimal?")] + public void MissingDecimalConstantAttribute_Method_ExplicitAttribute_WithDefault(string type) + { + var source = $$""" + using System.Runtime.CompilerServices; + + var m = C.M; + + class C + { + public static void M([DecimalConstant(1, 0, 0u, 0u, 11u)] {{type}} d = 1.1m) { } + } + """; + var comp = CreateCompilation(source); + comp.MakeTypeMissing(WellKnownType.System_Runtime_CompilerServices_DecimalConstantAttribute); + comp.VerifyDiagnostics( + // (3,9): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.DecimalConstantAttribute..ctor' + // var m = C.M; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "C.M").WithArguments("System.Runtime.CompilerServices.DecimalConstantAttribute", ".ctor").WithLocation(3, 9)); + } + + [Theory, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + [InlineData("decimal ")] + [InlineData("decimal?")] + public void MissingDecimalConstantAttribute_Method_ExplicitAttribute_WithDefault_CustomType(string type) + { + var source = $$""" + using System.Runtime.CompilerServices; + + Del m = C.M; + + class C + { + public static void M([DecimalConstant(1, 0, 0u, 0u, 11u)] {{type}} d = 1.1m) { } + } + + delegate void Del([DecimalConstant(1, 0, 0u, 0u, 11u)] {{type}} d = 1.1m); + """; + var comp = CreateCompilation(source); + comp.MakeTypeMissing(WellKnownType.System_Runtime_CompilerServices_DecimalConstantAttribute); + comp.VerifyEmitDiagnostics(); + } + + [Theory, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + [InlineData("decimal")] + [InlineData("decimal?")] + public void MissingDecimalConstantAttribute_ExternalMethodGroup(string type) + { + var source1 = $$""" + public class C + { + public static void M({{type}} d = 1.1m) { } + } + """; + var comp1 = CreateCompilation(source1).VerifyDiagnostics(); + + var source2 = """ + var m = C.M; + """; + var comp2 = CreateCompilation(source2, new[] { comp1.ToMetadataReference() }); + comp2.MakeTypeMissing(WellKnownType.System_Runtime_CompilerServices_DecimalConstantAttribute); + comp2.VerifyDiagnostics( + // (1,9): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.DecimalConstantAttribute..ctor' + // var m = C.M; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "C.M").WithArguments("System.Runtime.CompilerServices.DecimalConstantAttribute", ".ctor").WithLocation(1, 9)); + } + + [Theory, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + [InlineData("decimal")] + [InlineData("decimal?")] + public void MissingDecimalConstantAttribute_ExternalMethodGroup_CustomType(string type) + { + var source1 = $$""" + public delegate void Del({{type}} d = 1.1m); + + public class C + { + public static void M({{type}} d = 1.1m) { } + } + """; + var comp1 = CreateCompilation(source1).VerifyDiagnostics(); + + var source2 = """ + Del m = C.M; + """; + var comp2 = CreateCompilation(source2, new[] { comp1.ToMetadataReference() }); + comp2.MakeTypeMissing(WellKnownType.System_Runtime_CompilerServices_DecimalConstantAttribute); + comp2.VerifyEmitDiagnostics(); + } + + [Fact, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + public void MissingDecimalConstantAttribute_Field() + { + var source = """ + class C + { + public const decimal D = 1.1m; + } + """; + var comp = CreateCompilation(source); + comp.MakeTypeMissing(WellKnownType.System_Runtime_CompilerServices_DecimalConstantAttribute); + comp.VerifyDiagnostics( + // (3,26): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.DecimalConstantAttribute..ctor' + // public const decimal D = 1.1m; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "D = 1.1m").WithArguments("System.Runtime.CompilerServices.DecimalConstantAttribute", ".ctor").WithLocation(3, 26)); + } + + [Fact, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + public void MissingDecimalConstantAttribute_Field_ExplicitAttribute_Alone() + { + var source = """ + public static class C + { + [System.Runtime.CompilerServices.DecimalConstant(1, 0, 0u, 0u, 11u)] + public static readonly decimal D; + } + """; + var comp = CreateCompilation(source); + comp.MakeTypeMissing(WellKnownType.System_Runtime_CompilerServices_DecimalConstantAttribute); + comp.VerifyDiagnostics(); + + // Even though we use `static readonly` above, it's actually equivalent to `const` as demonstrated below. + var source2 = """ + const decimal d = C.D; + """; + CreateCompilation(source2, new[] { comp.EmitToImageReference() }).VerifyEmitDiagnostics( + // (1,15): warning CS0219: The variable 'd' is assigned but its value is never used + // const decimal d = C.D; + Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "d").WithArguments("d").WithLocation(1, 15)); + } + + [Fact, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + public void MissingDecimalConstantAttribute_Field_ExplicitAttribute_WithDefault() + { + var source = """ + class C + { + [System.Runtime.CompilerServices.DecimalConstant(1, 0, 0u, 0u, 11u)] + public const decimal D = 1.1m; + } + """; + var comp = CreateCompilation(source); + comp.MakeTypeMissing(WellKnownType.System_Runtime_CompilerServices_DecimalConstantAttribute); + comp.VerifyEmitDiagnostics(); + } + + [Fact, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + public void MissingDecimalConstantAttribute_OverloadResolution() + { + var source1 = """ + public delegate void Del(decimal d = 1.1m); + + public class C + { + public void M(Del d) { } + public void M(System.Action d) { } + } + """; + var comp1 = CreateCompilation(source1).VerifyDiagnostics(); + + var source2 = """ + new C().M((decimal d = 1.1m) => { }); + """; + + var diagnostics = new[] + { + // (1,9): error CS0121: The call is ambiguous between the following methods or properties: 'C.M(Del)' and 'C.M(Action)' + // new C().M((decimal d = 1.1m) => { }); + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("C.M(Del)", "C.M(System.Action)").WithLocation(1, 9) + }; + + var comp2 = CreateCompilation(source2, new[] { comp1.ToMetadataReference() }); + comp2.MakeTypeMissing(WellKnownType.System_Runtime_CompilerServices_DecimalConstantAttribute); + comp2.VerifyDiagnostics(diagnostics); + + comp2 = CreateCompilation(source2, new[] { comp1.ToMetadataReference() }); + comp2.MakeMemberMissing(WellKnownMember.System_Runtime_CompilerServices_DecimalConstantAttribute__ctor); + comp2.VerifyDiagnostics(diagnostics); + + comp2 = CreateCompilation(source2, new[] { comp1.ToMetadataReference() }); + comp2.MakeMemberMissing(WellKnownMember.System_Runtime_CompilerServices_DecimalConstantAttribute__ctorByteByteInt32Int32Int32); + comp2.VerifyDiagnostics(diagnostics); + + comp2 = CreateCompilation(source2, new[] { comp1.ToMetadataReference() }); + comp2.VerifyDiagnostics(diagnostics); + } + + [Theory, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + [InlineData("DateTime", "System.DateTime")] + [InlineData("DateTime?", "System.Nullable`1[System.DateTime]")] + public void MissingDateTimeConstantAttribute_Lambda_Alone(string type, string typeFullName) + { + var source = $$""" + using System; + using System.Runtime.CompilerServices; + + var lam = ([DateTimeConstant(100L)] {{type}} d) => { }; + System.Console.WriteLine(lam.GetType()); + var lam2 = lam; + System.Console.WriteLine(lam2.GetType()); + """; + var comp = CreateCompilation(source); + comp.MakeTypeMissing(WellKnownType.System_Runtime_CompilerServices_DateTimeConstantAttribute); + CompileAndVerify(comp, expectedOutput: $""" + System.Action`1[{typeFullName}] + System.Action`1[{typeFullName}] + """).VerifyDiagnostics(); + } + + [Theory, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + [InlineData("DateTime")] + [InlineData("DateTime?")] + public void MissingDateTimeConstantAttribute_Lambda_Alone_CustomType(string type) + { + var source = $$""" + using System; + using System.Runtime.CompilerServices; + + Del lam = ([DateTimeConstant(100L)] {{type}} d) => { }; + + delegate void Del([DateTimeConstant(100L)] {{type}} d); + """; + var comp = CreateCompilation(source); + comp.MakeTypeMissing(WellKnownType.System_Runtime_CompilerServices_DateTimeConstantAttribute); + comp.VerifyEmitDiagnostics(); + } + + [Theory, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + [InlineData("DateTime ")] + [InlineData("DateTime?")] + public void MissingDateTimeConstantAttribute_Lambda_WithOptional(string type) + { + var source = $$""" + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + var lam = ([Optional, DateTimeConstant(100L)] {{type}} d) => { }; + var lam2 = lam; + """; + + var diagnostics = new[] + { + // (5,57): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.DateTimeConstantAttribute..ctor' + // var lam = ([Optional, DateTimeConstant(100L)] DateTime d) => { }; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "d").WithArguments("System.Runtime.CompilerServices.DateTimeConstantAttribute", ".ctor").WithLocation(5, 57) + }; + + var comp = CreateCompilation(source); + comp.MakeTypeMissing(WellKnownType.System_Runtime_CompilerServices_DateTimeConstantAttribute); + comp.VerifyDiagnostics(diagnostics); + + comp = CreateCompilation(source); + comp.MakeMemberMissing(WellKnownMember.System_Runtime_CompilerServices_DateTimeConstantAttribute__ctor); + comp.VerifyDiagnostics(diagnostics); + } + + [Theory, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + [InlineData("DateTime ")] + [InlineData("DateTime?")] + public void MissingDateTimeConstantAttribute_Lambda_WithOptional_CustomType(string type) + { + var source = $$""" + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + Del lam = ([Optional, DateTimeConstant(100L)] {{type}} d) => { }; + + delegate void Del([Optional, DateTimeConstant(100L)] {{type}} d); + """; + var comp = CreateCompilation(source); + comp.MakeTypeMissing(WellKnownType.System_Runtime_CompilerServices_DateTimeConstantAttribute); + comp.VerifyEmitDiagnostics(); + } + + [Theory, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + [InlineData("DateTime ")] + [InlineData("DateTime?")] + public void MissingDateTimeConstantAttribute_ExternalMethodGroup(string type) + { + var source1 = $$""" + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + public class C + { + public static void M([Optional, DateTimeConstant(100L)] {{type}} d) { } + } + """; + var comp1 = CreateCompilation(source1).VerifyDiagnostics(); + + var source2 = """ + var m = C.M; + """; + var comp2 = CreateCompilation(source2, new[] { comp1.ToMetadataReference() }); + comp2.MakeTypeMissing(WellKnownType.System_Runtime_CompilerServices_DateTimeConstantAttribute); + comp2.VerifyDiagnostics( + // (1,9): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.DateTimeConstantAttribute..ctor' + // var m = C.M; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "C.M").WithArguments("System.Runtime.CompilerServices.DateTimeConstantAttribute", ".ctor").WithLocation(1, 9)); + } + + [Theory, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + [InlineData("DateTime ")] + [InlineData("DateTime?")] + public void MissingDateTimeConstantAttribute_ExternalMethodGroup_CustomType(string type) + { + var source1 = $$""" + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + public delegate void Del([Optional, DateTimeConstant(100L)] {{type}} d); + + public class C + { + public static void M([Optional, DateTimeConstant(100L)] {{type}} d) { } + } + """; + var comp1 = CreateCompilation(source1).VerifyDiagnostics(); + + var source2 = """ + Del m = C.M; + """; + var comp2 = CreateCompilation(source2, new[] { comp1.ToMetadataReference() }); + comp2.MakeTypeMissing(WellKnownType.System_Runtime_CompilerServices_DateTimeConstantAttribute); + comp2.VerifyEmitDiagnostics(); + } + + [Fact, WorkItem(65728, "https://github.com/dotnet/roslyn/issues/65728")] + public void MissingDateTimeConstantAttribute_OverloadResolution() + { + var source1 = """ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + public delegate void Del([Optional, DateTimeConstant(100L)] DateTime d); + + public class C + { + public void M(Del d) { } + public void M(Action d) { } + } + """; + var comp1 = CreateCompilation(source1).VerifyDiagnostics(); + + var source2 = """ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + new C().M(([Optional, DateTimeConstant(100L)] DateTime d) => { }); + """; + + var diagnostics = new[] + { + // (5,9): error CS0121: The call is ambiguous between the following methods or properties: 'C.M(Del)' and 'C.M(Action)' + // new C().M(([Optional, DateTimeConstant(100L)] DateTime d) => { }); + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("C.M(Del)", "C.M(System.Action)").WithLocation(5, 9) + }; + + var comp2 = CreateCompilation(source2, new[] { comp1.ToMetadataReference() }); + comp2.MakeTypeMissing(WellKnownType.System_Runtime_CompilerServices_DateTimeConstantAttribute); + comp2.VerifyDiagnostics(diagnostics); + + comp2 = CreateCompilation(source2, new[] { comp1.ToMetadataReference() }); + comp2.MakeMemberMissing(WellKnownMember.System_Runtime_CompilerServices_DateTimeConstantAttribute__ctor); + comp2.VerifyDiagnostics(diagnostics); + + comp2 = CreateCompilation(source2, new[] { comp1.ToMetadataReference() }); + comp2.VerifyDiagnostics(diagnostics); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/InterpolationTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/InterpolationTests.cs index 7aaf5c7830dfe..d94f185aead71 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/InterpolationTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/InterpolationTests.cs @@ -11033,39 +11033,37 @@ Creating DummyHandler // Code size 88 (0x58) .maxstack 5 .locals init (T& V_0, - T V_1, - T& V_2, - T V_3, - DummyHandler V_4) + T V_1, + T& V_2, + DummyHandler V_3) IL_0000: ldarga.s V_0 IL_0002: stloc.2 - IL_0003: ldloca.s V_3 - IL_0005: initobj ""T"" - IL_000b: ldloc.3 - IL_000c: box ""T"" - IL_0011: brtrue.s IL_001e - IL_0013: ldloc.2 - IL_0014: ldobj ""T"" - IL_0019: stloc.1 - IL_001a: ldloca.s V_1 - IL_001c: br.s IL_001f - IL_001e: ldloc.2 - IL_001f: stloc.0 - IL_0020: ldloc.0 - IL_0021: ldloca.s V_4 - IL_0023: ldc.i4.4 - IL_0024: ldc.i4.1 - IL_0025: ldloc.0 - IL_0026: ldobj ""T"" - IL_002b: box ""T"" - IL_0030: call ""DummyHandler..ctor(int, int, ILogger)"" - IL_0035: ldloca.s V_4 - IL_0037: ldstr ""log:"" - IL_003c: call ""void DummyHandler.AppendLiteral(string)"" - IL_0041: ldloca.s V_4 - IL_0043: ldc.i4.m1 - IL_0044: call ""void DummyHandler.AppendFormatted(int)"" - IL_0049: ldloc.s V_4 + IL_0003: ldtoken ""T"" + IL_0008: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000d: call ""bool System.Type.IsValueType.get"" + IL_0012: brtrue.s IL_001f + IL_0014: ldloc.2 + IL_0015: ldobj ""T"" + IL_001a: stloc.1 + IL_001b: ldloca.s V_1 + IL_001d: br.s IL_0020 + IL_001f: ldloc.2 + IL_0020: stloc.0 + IL_0021: ldloc.0 + IL_0022: ldloca.s V_3 + IL_0024: ldc.i4.4 + IL_0025: ldc.i4.1 + IL_0026: ldloc.0 + IL_0027: ldobj ""T"" + IL_002c: box ""T"" + IL_0031: call ""DummyHandler..ctor(int, int, ILogger)"" + IL_0036: ldloca.s V_3 + IL_0038: ldstr ""log:"" + IL_003d: call ""void DummyHandler.AppendLiteral(string)"" + IL_0042: ldloca.s V_3 + IL_0044: ldc.i4.m1 + IL_0045: call ""void DummyHandler.AppendFormatted(int)"" + IL_004a: ldloc.3 IL_004b: constrained. ""T"" IL_0051: callvirt ""void ILogger.Log(DummyHandler)"" IL_0056: ldarg.0 @@ -11110,39 +11108,37 @@ .locals init (T& V_0, // Code size 87 (0x57) .maxstack 5 .locals init (T& V_0, - T V_1, - T& V_2, - T V_3, - DummyHandler V_4) + T V_1, + T& V_2, + DummyHandler V_3) IL_0000: ldarg.0 IL_0001: stloc.2 - IL_0002: ldloca.s V_3 - IL_0004: initobj ""T"" - IL_000a: ldloc.3 - IL_000b: box ""T"" - IL_0010: brtrue.s IL_001d - IL_0012: ldloc.2 - IL_0013: ldobj ""T"" - IL_0018: stloc.1 - IL_0019: ldloca.s V_1 - IL_001b: br.s IL_001e - IL_001d: ldloc.2 - IL_001e: stloc.0 - IL_001f: ldloc.0 - IL_0020: ldloca.s V_4 - IL_0022: ldc.i4.4 - IL_0023: ldc.i4.1 - IL_0024: ldloc.0 - IL_0025: ldobj ""T"" - IL_002a: box ""T"" - IL_002f: call ""DummyHandler..ctor(int, int, ILogger)"" - IL_0034: ldloca.s V_4 - IL_0036: ldstr ""log:"" - IL_003b: call ""void DummyHandler.AppendLiteral(string)"" - IL_0040: ldloca.s V_4 - IL_0042: ldc.i4.s -3 - IL_0044: call ""void DummyHandler.AppendFormatted(int)"" - IL_0049: ldloc.s V_4 + IL_0002: ldtoken ""T"" + IL_0007: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000c: call ""bool System.Type.IsValueType.get"" + IL_0011: brtrue.s IL_001e + IL_0013: ldloc.2 + IL_0014: ldobj ""T"" + IL_0019: stloc.1 + IL_001a: ldloca.s V_1 + IL_001c: br.s IL_001f + IL_001e: ldloc.2 + IL_001f: stloc.0 + IL_0020: ldloc.0 + IL_0021: ldloca.s V_3 + IL_0023: ldc.i4.4 + IL_0024: ldc.i4.1 + IL_0025: ldloc.0 + IL_0026: ldobj ""T"" + IL_002b: box ""T"" + IL_0030: call ""DummyHandler..ctor(int, int, ILogger)"" + IL_0035: ldloca.s V_3 + IL_0037: ldstr ""log:"" + IL_003c: call ""void DummyHandler.AppendLiteral(string)"" + IL_0041: ldloca.s V_3 + IL_0043: ldc.i4.s -3 + IL_0045: call ""void DummyHandler.AppendFormatted(int)"" + IL_004a: ldloc.3 IL_004b: constrained. ""T"" IL_0051: callvirt ""void ILogger.Log(DummyHandler)"" IL_0056: ret @@ -11287,18 +11283,16 @@ Creating DummyHandler // Code size 110 (0x6e) .maxstack 4 .locals init (T& V_0, - T V_1, - T& V_2, - DummyHandler V_3, - T V_4, - DummyHandler V_5) + T V_1, + T& V_2, + DummyHandler V_3, + DummyHandler V_4) IL_0000: ldarg.0 IL_0001: call ""ref T Program.<
$>g__get3|0_2(ref T)"" IL_0006: stloc.2 - IL_0007: ldloca.s V_4 - IL_0009: initobj ""T"" - IL_000f: ldloc.s V_4 - IL_0011: box ""T"" + IL_0007: ldtoken ""T"" + IL_000c: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0011: call ""bool System.Type.IsValueType.get"" IL_0016: brtrue.s IL_0023 IL_0018: ldloc.2 IL_0019: ldobj ""T"" @@ -11307,20 +11301,20 @@ .locals init (T& V_0, IL_0021: br.s IL_0024 IL_0023: ldloc.2 IL_0024: stloc.0 - IL_0025: ldloca.s V_5 + IL_0025: ldloca.s V_4 IL_0027: ldc.i4.4 IL_0028: ldc.i4.1 IL_0029: ldloc.0 IL_002a: ldobj ""T"" IL_002f: box ""T"" IL_0034: call ""DummyHandler..ctor(int, int, ILogger)"" - IL_0039: ldloca.s V_5 + IL_0039: ldloca.s V_4 IL_003b: ldstr ""log:"" IL_0040: call ""void DummyHandler.AppendLiteral(string)"" - IL_0045: ldloca.s V_5 + IL_0045: ldloca.s V_4 IL_0047: ldc.i4.s -3 IL_0049: call ""void DummyHandler.AppendFormatted(int)"" - IL_004e: ldloc.s V_5 + IL_004e: ldloc.s V_4 IL_0050: stloc.3 IL_0051: ldloc.0 IL_0052: ldloc.3 @@ -14924,6 +14918,160 @@ static CustomHandler F4() comp.VerifyDiagnostics(); } + [Fact] + public void RefEscape_14() + { + string source = """ + using System.Runtime.CompilerServices; + [InterpolatedStringHandler] + struct CustomHandler + { + public CustomHandler(int literalLength, int formattedCount) { } + } + ref struct R { } + class Program + { + static R F1() + { + R r = F2($""); + return r; + } + static R F2(ref CustomHandler handler) + { + return default; + } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyDiagnostics( + // (13,16): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope + // return r; + Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(13, 16)); + } + + [Fact] + public void RefEscape_15() + { + string source = """ + using System.Runtime.CompilerServices; + [InterpolatedStringHandler] + ref struct CustomHandler + { + public CustomHandler(int literalLength, int formattedCount, ref R r) : this() { r.Handler = this; } + public void AppendFormatted(int i) { } + } + ref struct R + { + public CustomHandler Handler; + public object this[[InterpolatedStringHandlerArgument("")] CustomHandler handler] => null; + } + class Program + { + static R F() + { + R r = new R(); + _ = r[$"{1}"]; + return r; + } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyDiagnostics( + // (5,97): error CS8352: Cannot use variable 'out CustomHandler this' in this context because it may expose referenced variables outside of their declaration scope + // public CustomHandler(int literalLength, int formattedCount, ref R r) : this() { r.Handler = this; } + Diagnostic(ErrorCode.ERR_EscapeVariable, "this").WithArguments("out CustomHandler this").WithLocation(5, 97), + // (18,13): error CS1620: Argument 3 must be passed with the 'ref' keyword + // _ = r[$"{1}"]; + Diagnostic(ErrorCode.ERR_BadArgRef, "r").WithArguments("3", "ref").WithLocation(18, 13)); + } + + [Fact] + public void RefEscape_16() + { + string source = """ + using System.Runtime.CompilerServices; + [InterpolatedStringHandler] + ref struct CustomHandler + { + public CustomHandler(int literalLength, int formattedCount, ref R r) : this() { r.Handler = this; } + public void AppendFormatted(int i) { } + } + ref struct R + { + public CustomHandler Handler; + public object this[ref R r, [InterpolatedStringHandlerArgument("r")] CustomHandler handler] => null; + } + class Program + { + static R F() + { + R r = new R(); + _ = r[ref r, $"{1}"]; + return r; + } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyDiagnostics( + // (5,97): error CS8352: Cannot use variable 'out CustomHandler this' in this context because it may expose referenced variables outside of their declaration scope + // public CustomHandler(int literalLength, int formattedCount, ref R r) : this() { r.Handler = this; } + Diagnostic(ErrorCode.ERR_EscapeVariable, "this").WithArguments("out CustomHandler this").WithLocation(5, 97), + // (11,24): error CS0631: ref and out are not valid in this context + // public object this[ref R r, [InterpolatedStringHandlerArgument("r")] CustomHandler handler] => null; + Diagnostic(ErrorCode.ERR_IllegalRefParam, "ref").WithLocation(11, 24), + // (18,19): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference + // _ = r[ref r, $"{1}"]; + Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "r").WithLocation(18, 19), + // (18,19): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference + // _ = r[ref r, $"{1}"]; + Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "r").WithLocation(18, 19), + // (18,22): error CS8347: Cannot use a result of 'CustomHandler.CustomHandler(int, int, ref R)' in this context because it may expose variables referenced by parameter 'r' outside of their declaration scope + // _ = r[ref r, $"{1}"]; + Diagnostic(ErrorCode.ERR_EscapeCall, @"$""{1}""").WithArguments("CustomHandler.CustomHandler(int, int, ref R)", "r").WithLocation(18, 22), + // (18,22): error CS8347: Cannot use a result of 'CustomHandler.CustomHandler(int, int, ref R)' in this context because it may expose variables referenced by parameter 'r' outside of their declaration scope + // _ = r[ref r, $"{1}"]; + Diagnostic(ErrorCode.ERR_EscapeCall, @"$""{1}""").WithArguments("CustomHandler.CustomHandler(int, int, ref R)", "r").WithLocation(18, 22)); + } + + [Fact] + public void RefEscape_17() + { + string source = """ + using System.Runtime.CompilerServices; + [InterpolatedStringHandler] + ref struct CustomHandler + { + public CustomHandler(int literalLength, int formattedCount, ref R r) : this() { r.Handler = this; } + public void AppendFormatted(int i) { } + } + ref struct R + { + public CustomHandler Handler; + public R(ref R r, [InterpolatedStringHandlerArgument("r")] CustomHandler handler) { } + } + class Program + { + static R F() + { + R x = new R(); + R y = new R(ref x, $"{1}"); + return x; + } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyDiagnostics( + // (5,97): error CS8352: Cannot use variable 'out CustomHandler this' in this context because it may expose referenced variables outside of their declaration scope + // public CustomHandler(int literalLength, int formattedCount, ref R r) : this() { r.Handler = this; } + Diagnostic(ErrorCode.ERR_EscapeVariable, "this").WithArguments("out CustomHandler this").WithLocation(5, 97), + // (18,25): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference + // R y = new R(ref x, $"{1}"); + Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "x").WithLocation(18, 25), + // (18,28): error CS8347: Cannot use a result of 'CustomHandler.CustomHandler(int, int, ref R)' in this context because it may expose variables referenced by parameter 'r' outside of their declaration scope + // R y = new R(ref x, $"{1}"); + Diagnostic(ErrorCode.ERR_EscapeCall, @"$""{1}""").WithArguments("CustomHandler.CustomHandler(int, int, ref R)", "r").WithLocation(18, 28)); + } + [Theory, WorkItem(54703, "https://github.com/dotnet/roslyn/issues/54703")] [InlineData(@"$""{{ {i} }}""")] [InlineData(@"$""{{ "" + $""{i}"" + $"" }}""")] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs index af28e95a5480d..5511b8ee8cfbe 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs @@ -1238,10 +1238,7 @@ class C Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "r").WithArguments("R", "R").WithLocation(13, 24), // (15,24): error CS8168: Cannot return local 'r' by reference because it is not a ref local // return ref r!; // 2 - Diagnostic(ErrorCode.ERR_RefReturnLocal, "r").WithArguments("r").WithLocation(15, 24), - // (15,24): warning CS8619: Nullability of reference types in value of type 'R' doesn't match target type 'R'. - // return ref r!; // 2 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "r").WithArguments("R", "R").WithLocation(15, 24)); + Diagnostic(ErrorCode.ERR_RefReturnLocal, "r").WithArguments("r").WithLocation(15, 24)); } [WorkItem(31297, "https://github.com/dotnet/roslyn/issues/31297")] @@ -156560,5 +156557,155 @@ public A(string _) {} // var lam = ([A(nameof(lam))] int x) => { }; Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "lam").WithArguments("lam").WithLocation(7, 30)); } + + [Fact, WorkItem(61516, "https://github.com/dotnet/roslyn/issues/61516")] + public void NestedMethodAnalysis_Repro61516() + { + var source = """ +#nullable enable +using System.Linq; + +static void DoSomething() +{ + var plans = Enumerable.Empty(); + + var filtered = plans.Select( + plan => new { Value = plan.Schedule } + ); +} + +DoSomething(); + +class Plan +{ + public object? Schedule + { + get; + set; + } +} +"""; + CreateCompilation(source).VerifyDiagnostics(); + + source = """ +#nullable enable +using System.Linq; + +static object? GetTask() +{ + return new object(); +} + +static void DoSomething() +{ + var plans = Enumerable.Empty(); + + var filtered = plans.Select( + plan => new { Value = plan.Schedule } + ); + + var tasks = filtered.Select(anon => GetTask()); +} + +DoSomething(); + +class Plan +{ + public object? Schedule + { + get; + set; + } +} +"""; + CreateCompilation(source).VerifyDiagnostics(); + } + + [Fact, WorkItem(61964, "https://github.com/dotnet/roslyn/issues/61964")] + public void NestedMethodAnalysis_Repro61964() + { + var source = """ +using System.Collections.Generic; +using System.Linq; + +#nullable disable +public class Widget { public string Name; } + +#nullable enable +record Goo(Bar? Bar); +record Bar(Baz? Baz); +record Baz(); + +class UsesNullObliviousType +{ + public static void DoWork(List list, Widget widget) + { + var baz = list.Select(x => x.Bar.Baz); // 1 + + for (int i = 0; i < 10; i++) + { + var x = widget.Name; + } + } +} + +class UsesNullObliviousTypeAndDoesNullCheck +{ + public static void DoWork(List list, Widget widget) + { + var baz = list.Select(x => x.Bar.Baz); // 2 + + for (int i = 0; i < 10; i++) + { + if (widget.Name is null) + { + } + } + } +} + +class UsesNonNullableType +{ + public static void DoWork(List list, string unrelatedObject) + { + var baz = list.Select(x => x.Bar.Baz); // 3 + + for (int i = 0; i < 10; i++) + { + var x = unrelatedObject; + } + } +} + +class UsesNonNullableTypeAndDoesNullCheck +{ + public static void DoWork(List list, string unrelatedObject) + { + var baz = list.Select(x => x.Bar.Baz); // 4 + + for (int i = 0; i < 10; i++) + { + if (unrelatedObject is null) + { + } + } + } +} +"""; + CreateCompilation(source, targetFramework: TargetFramework.Net70).VerifyDiagnostics( + // (16,36): warning CS8602: Dereference of a possibly null reference. + // var baz = list.Select(x => x.Bar.Baz); // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x.Bar").WithLocation(16, 36), + // (29,36): warning CS8602: Dereference of a possibly null reference. + // var baz = list.Select(x => x.Bar.Baz); // 2 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x.Bar").WithLocation(29, 36), + // (44,36): warning CS8602: Dereference of a possibly null reference. + // var baz = list.Select(x => x.Bar.Baz); // 3 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x.Bar").WithLocation(44, 36), + // (57,36): warning CS8602: Dereference of a possibly null reference. + // var baz = list.Select(x => x.Bar.Baz); // 4 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x.Bar").WithLocation(57, 36) + ); + } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs index 49fff34aa127f..a2161cd73539b 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs @@ -176,17 +176,25 @@ public void RefStructEscapeInIterator(LanguageVersion languageVersion) using System.Collections; class C { - IEnumerable Gen() + IEnumerable F1() { - Span s = stackalloc int[10]; - yield return s; + Span s1 = stackalloc int[10]; + yield return s1; + } + IEnumerable F2() + { + Span s2 = default; + yield return s2; } }", parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); // Note: an escape analysis error is not given here because we already gave a conversion error. comp.VerifyDiagnostics( // (9,22): error CS0029: Cannot implicitly convert type 'System.Span' to 'object' - // yield return s; - Diagnostic(ErrorCode.ERR_NoImplicitConv, "s").WithArguments("System.Span", "object").WithLocation(9, 22)); + // yield return s1; + Diagnostic(ErrorCode.ERR_NoImplicitConv, "s1").WithArguments("System.Span", "object").WithLocation(9, 22), + // (14,22): error CS0029: Cannot implicitly convert type 'System.Span' to 'object' + // yield return s2; + Diagnostic(ErrorCode.ERR_NoImplicitConv, "s2").WithArguments("System.Span", "object").WithLocation(14, 22)); } [Theory] @@ -889,8 +897,8 @@ static ref int ReturnsRef(out int x) ); } - [Fact()] - public void DiscardExpressionSpan() + [Fact] + public void DiscardExpressionSpan_01() { var text = @" using System; @@ -914,7 +922,7 @@ static Span Test2() ref var s = ref ReturnsSpan(out var _); // error - s = stackalloc int[1]; + s = stackalloc int[1]; // 1 // ok return s; @@ -923,33 +931,33 @@ static Span Test2() static void Test3() { // error - ReturnsSpan(out var _ ) = stackalloc int[1]; + ReturnsSpan(out var _ ) = stackalloc int[1]; // 2 } static ref Span ReturnsSpan(out Span x) { x = default; - return ref x; + return ref x; // 3 } } "; CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular10).VerifyDiagnostics( // (23,13): error CS8353: A result of a stackalloc expression of type 'Span' cannot be used in this context because it may be exposed outside of the containing method - // s = stackalloc int[1]; + // s = stackalloc int[1]; // 1 Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc int[1]").WithArguments("System.Span").WithLocation(23, 13), // (32,35): error CS8353: A result of a stackalloc expression of type 'Span' cannot be used in this context because it may be exposed outside of the containing method - // ReturnsSpan(out var _ ) = stackalloc int[1]; + // ReturnsSpan(out var _ ) = stackalloc int[1]; // 2 Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc int[1]").WithArguments("System.Span").WithLocation(32, 35) ); CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( // (23,13): error CS8353: A result of a stackalloc expression of type 'Span' cannot be used in this context because it may be exposed outside of the containing method - // s = stackalloc int[1]; + // s = stackalloc int[1]; // 1 Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc int[1]").WithArguments("System.Span").WithLocation(23, 13), // (32,35): error CS8353: A result of a stackalloc expression of type 'Span' cannot be used in this context because it may be exposed outside of the containing method - // ReturnsSpan(out var _ ) = stackalloc int[1]; + // ReturnsSpan(out var _ ) = stackalloc int[1]; // 2 Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc int[1]").WithArguments("System.Span").WithLocation(32, 35), // (38,20): error CS9075: Cannot return a parameter by reference 'x' because it is scoped to the current method - // return ref x; + // return ref x; // 3 Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "x").WithArguments("x").WithLocation(38, 20) ); } @@ -1068,6 +1076,575 @@ .locals init (System.Span V_0, "); } + // As above with 'out _' instead of 'out var _'. + [WorkItem(65651, "https://github.com/dotnet/roslyn/issues/65651")] + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void DiscardExpressionSpan_02(LanguageVersion languageVersion) + { + string source = """ + using System; + class Program + { + static Span Test2A() + { + ref var s2A = ref ReturnsSpan(out _); + s2A = stackalloc int[1]; // 1 + return s2A; + } + static Span Test2B() + { + Span _; + ref var s2B = ref ReturnsSpan(out _); + s2B = stackalloc int[1]; // 2 + return s2B; + } + static void Test3A() + { + ReturnsSpan(out _ ) = stackalloc int[1]; // 3 + } + static void Test3B() + { + Span _; + ReturnsSpan(out _ ) = stackalloc int[1]; // 4 + } + static ref Span ReturnsSpan(out Span x) + { + throw null; + } + } + """; + var comp = CreateCompilationWithMscorlibAndSpan(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyDiagnostics( + // (7,15): error CS8353: A result of a stackalloc expression of type 'Span' cannot be used in this context because it may be exposed outside of the containing method + // s2A = stackalloc int[1]; // 1 + Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc int[1]").WithArguments("System.Span").WithLocation(7, 15), + // (14,15): error CS8353: A result of a stackalloc expression of type 'Span' cannot be used in this context because it may be exposed outside of the containing method + // s2B = stackalloc int[1]; // 2 + Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc int[1]").WithArguments("System.Span").WithLocation(14, 15), + // (19,31): error CS8353: A result of a stackalloc expression of type 'Span' cannot be used in this context because it may be exposed outside of the containing method + // ReturnsSpan(out _ ) = stackalloc int[1]; // 3 + Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc int[1]").WithArguments("System.Span").WithLocation(19, 31), + // (24,31): error CS8353: A result of a stackalloc expression of type 'Span' cannot be used in this context because it may be exposed outside of the containing method + // ReturnsSpan(out _ ) = stackalloc int[1]; // 4 + Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc int[1]").WithArguments("System.Span").WithLocation(24, 31)); + } + + // ReturnsSpan() returns ref Span, callers return Span by value. + [WorkItem(65651, "https://github.com/dotnet/roslyn/issues/65651")] + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void DiscardExpressionSpan_03(LanguageVersion languageVersion) + { + string source = """ + using System; + class Program + { + static Span Test1() + { + var s1 = ReturnsSpan(out _); + return s1; + } + static Span Test2() + { + var s2 = ReturnsSpan(out var _); + return s2; + } + static Span Test3() + { + var s3 = ReturnsSpan(out Span _); + return s3; + } + static Span Test4() + { + var s4 = ReturnsSpan(out var unused); + return s4; + } + static Span Test5() + { + Span _; + var s5 = ReturnsSpan(out _); + return s5; + } + static Span Test6(out Span _) + { + var s6 = ReturnsSpan(out _); + return s6; + } + static ref Span ReturnsSpan(out Span x) + { + throw null; + } + } + """; + var comp = CreateCompilationWithMscorlibAndSpan(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyDiagnostics(); + } + + // ReturnsSpan() and callers return Span by value. + [WorkItem(65651, "https://github.com/dotnet/roslyn/issues/65651")] + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void DiscardExpressionSpan_04(LanguageVersion languageVersion) + { + string source = """ + using System; + class Program + { + static Span Test1() + { + var s1 = ReturnsSpan(out _); + return s1; + } + static Span Test2() + { + var s2 = ReturnsSpan(out var _); + return s2; + } + static Span Test3() + { + var s3 = ReturnsSpan(out Span _); + return s3; + } + static Span Test4() + { + var s4 = ReturnsSpan(out var unused); + return s4; + } + static Span Test5() + { + Span _; + var s5 = ReturnsSpan(out _); + return s5; + } + static Span Test6(out Span _) + { + var s6 = ReturnsSpan(out _); + return s6; + } + static Span ReturnsSpan(out Span x) + { + x = default; + return x; + } + } + """; + var comp = CreateCompilationWithMscorlibAndSpan(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyDiagnostics(); + } + + // ReturnsSpan() and callers return ref Span. + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void DiscardExpressionSpan_05(LanguageVersion languageVersion) + { + string source = """ + using System; + class Program + { + static ref Span Test1() + { + var s1 = ReturnsSpan(out _); + return ref s1; // 1 + } + static ref Span Test2() + { + var s2 = ReturnsSpan(out var _); + return ref s2; // 2 + } + static ref Span Test3() + { + var s3 = ReturnsSpan(out Span _); + return ref s3; // 3 + } + static ref Span Test4() + { + var s4 = ReturnsSpan(out var unused); + return ref s4; // 4 + } + static ref Span Test5() + { + Span _; + var s5 = ReturnsSpan(out _); + return ref s5; // 5 + } + static ref Span Test6(out Span _) + { + var s6 = ReturnsSpan(out _); + return ref s6; // 6 + } + static ref Span ReturnsSpan(out Span x) + { + throw null; + } + } + """; + var comp = CreateCompilationWithMscorlibAndSpan(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyDiagnostics( + // (7,20): error CS8168: Cannot return local 's1' by reference because it is not a ref local + // return ref s1; // 1 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "s1").WithArguments("s1").WithLocation(7, 20), + // (12,20): error CS8168: Cannot return local 's2' by reference because it is not a ref local + // return ref s2; // 2 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "s2").WithArguments("s2").WithLocation(12, 20), + // (17,20): error CS8168: Cannot return local 's3' by reference because it is not a ref local + // return ref s3; // 3 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "s3").WithArguments("s3").WithLocation(17, 20), + // (22,20): error CS8168: Cannot return local 's4' by reference because it is not a ref local + // return ref s4; // 4 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "s4").WithArguments("s4").WithLocation(22, 20), + // (28,20): error CS8168: Cannot return local 's5' by reference because it is not a ref local + // return ref s5; // 5 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "s5").WithArguments("s5").WithLocation(28, 20), + // (33,20): error CS8168: Cannot return local 's6' by reference because it is not a ref local + // return ref s6; // 6 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "s6").WithArguments("s6").WithLocation(33, 20)); + } + + // ReturnsSpan() and callers return ref int. + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void DiscardExpressionSpan_06(LanguageVersion languageVersion) + { + string source = """ + class Program + { + static ref int Test1() + { + var s1 = ReturnsSpan(out _); + return ref s1; // 1 + } + static ref int Test2() + { + var s2 = ReturnsSpan(out var _); + return ref s2; // 2 + } + static ref int Test3() + { + var s3 = ReturnsSpan(out int _); + return ref s3; // 3 + } + static ref int Test4() + { + var s4 = ReturnsSpan(out var unused); + return ref s4; // 4 + } + static ref int Test5() + { + int _; + var s5 = ReturnsSpan(out _); + return ref s5; // 5 + } + static ref int Test6(out int _) + { + var s6 = ReturnsSpan(out _); + return ref s6; // 6 + } + static ref int ReturnsSpan(out int x) + { + throw null; + } + } + """; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyDiagnostics( + // (6,20): error CS8168: Cannot return local 's1' by reference because it is not a ref local + // return ref s1; // 1 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "s1").WithArguments("s1").WithLocation(6, 20), + // (11,20): error CS8168: Cannot return local 's2' by reference because it is not a ref local + // return ref s2; // 2 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "s2").WithArguments("s2").WithLocation(11, 20), + // (16,20): error CS8168: Cannot return local 's3' by reference because it is not a ref local + // return ref s3; // 3 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "s3").WithArguments("s3").WithLocation(16, 20), + // (21,20): error CS8168: Cannot return local 's4' by reference because it is not a ref local + // return ref s4; // 4 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "s4").WithArguments("s4").WithLocation(21, 20), + // (27,20): error CS8168: Cannot return local 's5' by reference because it is not a ref local + // return ref s5; // 5 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "s5").WithArguments("s5").WithLocation(27, 20), + // (32,20): error CS8168: Cannot return local 's6' by reference because it is not a ref local + // return ref s6; // 6 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "s6").WithArguments("s6").WithLocation(32, 20)); + } + + [Theory] + [InlineData("out var _")] + [InlineData("out _")] + [InlineData("out Span _")] + [InlineData("out var unused")] + [InlineData("out Span unused")] + public void DiscardExpressionSpan_07(string outVarDeclaration) + { + string source = $$""" + using System; + using System.Diagnostics.CodeAnalysis; + class Program + { + static Span Test1() + { + var s1 = ReturnsSpan({{outVarDeclaration}}); + return s1; + } + static Span Test2() + { + ref var s2 = ref ReturnsSpan({{outVarDeclaration}}); + s2 = stackalloc int[1]; // 1 + return s2; + } + static void Test3() + { + ReturnsSpan({{outVarDeclaration}}) = + stackalloc int[1]; // 2 + } + static ref Span ReturnsSpan([UnscopedRef] out Span x) + { + x = default; + return ref x; + } + } + """; + var comp = CreateCompilationWithMscorlibAndSpan(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics( + // (13,14): error CS8353: A result of a stackalloc expression of type 'Span' cannot be used in this context because it may be exposed outside of the containing method + // s2 = stackalloc int[1]; // 1 + Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc int[1]").WithArguments("System.Span").WithLocation(13, 14), + // (19,13): error CS8353: A result of a stackalloc expression of type 'Span' cannot be used in this context because it may be exposed outside of the containing method + // stackalloc int[1]; // 2 + Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc int[1]").WithArguments("System.Span").WithLocation(19, 13)); + } + + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void Discard_01(LanguageVersion languageVersion) + { + string source = """ + using System; + class Program + { + static void F1() + { + Span s1 = stackalloc int[1]; + _ = s1; + } + static void F2() + { + Span s2 = stackalloc int[1]; + Span _; + _ = s2; // 1 + } + } + """; + var comp = CreateCompilationWithMscorlibAndSpan(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyDiagnostics( + // (13,13): error CS8352: Cannot use variable 's2' in this context because it may expose referenced variables outside of their declaration scope + // _ = s2; // 1 + Diagnostic(ErrorCode.ERR_EscapeVariable, "s2").WithArguments("s2").WithLocation(13, 13)); + } + + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void Discard_02(LanguageVersion languageVersion) + { + string source = """ + class Program + { + static void F1(ref int x1) + { + int y1 = 1; + _ = ref y1; + _ = ref x1; + } + static void F2(ref int x2) + { + int y2 = 2; + _ = ref x2; + _ = ref y2; + } + static void F3() + { + int y3 = 3; + ref int _ = ref y3; + _ = ref y3; + } + static void F4(ref int x4) + { + int y4 = 4; + ref int _ = ref x4; + _ = ref y4; // 1 + } + } + """; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyDiagnostics( + // (25,9): error CS8374: Cannot ref-assign 'y4' to '_' because 'y4' has a narrower escape scope than '_'. + // _ = ref y4; // 1 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "_ = ref y4").WithArguments("_", "y4").WithLocation(25, 9)); + } + + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void Discard_03(LanguageVersion languageVersion) + { + var source = +@"class Program +{ + static void F1() + { + (var x1, _) = F(); + (var x2, var _) = F(); + (var x3, R _) = F(); + var (x4, _) = F(); + } + static void F2() + { + R _; + (var x5, _) = F(); + } + static R F() => default; +} +ref struct R +{ + public void Deconstruct(out R x, out R y) => throw null; +} +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyEmitDiagnostics(); + } + + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void Discard_04(LanguageVersion languageVersion) + { + var source = +@"using System; +class Program +{ + static void F1() + { + Span s1 = default; + s1.Deconstruct(out s1, out _); + } + static void F2() + { + Span s2 = default; + (s2, _) = s2; + } + static void F3() + { + Span s3 = default; + s3.Deconstruct(out s3, out var _); + } + static void F4() + { + Span s4 = default; + (s4, var _) = s4; + } + static void F5() + { + Span s5 = default; + s5.Deconstruct(out s5, out Span _); + } + static void F6() + { + Span s6 = default; + (s6, Span _) = s6; + } + static void F7() + { + Span s7 = default; + s7.Deconstruct(out s7, out var unused); + } + static void F8() + { + Span s8 = default; + (s8, var unused) = s8; + } +} +static class Extensions +{ + public static void Deconstruct(this Span self, out Span x, out Span y) + { + throw null; + } +} +"; + var comp = CreateCompilationWithMscorlibAndSpan(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyEmitDiagnostics(); + } + + [WorkItem(65522, "https://github.com/dotnet/roslyn/issues/65522")] + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void Discard_05(LanguageVersion languageVersion) + { + var source = +@"using System; +class Program +{ + static void F1() + { + Span s1 = stackalloc int[10]; + s1.Deconstruct(out s1, out _); + } + static void F2() + { + Span s2 = stackalloc int[10]; + (s2, _) = s2; + } + static void F3() + { + Span s3 = stackalloc int[10]; + s3.Deconstruct(out s3, out var _); + } + static void F4() + { + Span s4 = stackalloc int[10]; + (s4, var _) = s4; + } + static void F5() + { + Span s5 = stackalloc int[10]; + s5.Deconstruct(out s5, out Span _); + } + static void F6() + { + Span s6 = stackalloc int[10]; + (s6, Span _) = s6; + } + static void F7() + { + Span s7 = stackalloc int[10]; + s7.Deconstruct(out s7, out var unused); + } + static void F8() + { + Span s8 = stackalloc int[10]; + (s8, var unused) = s8; + } +} +static class Extensions +{ + public static void Deconstruct(this Span self, out Span x, out Span y) + { + throw null; + } +} +"; + var comp = CreateCompilationWithMscorlibAndSpan(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyEmitDiagnostics(); + } + [Fact()] public void OrdinaryLocalAndOutSpan() { @@ -3459,6 +4036,7 @@ .maxstack 1 "); } + [WorkItem(65522, "https://github.com/dotnet/roslyn/issues/65522")] [Theory] [InlineData(LanguageVersion.CSharp10)] [InlineData(LanguageVersion.CSharp11)] @@ -3510,13 +4088,7 @@ public static void Deconstruct(this Span self, out Span x, out Span, out Span, out Span)' is disallowed because it may expose variables referenced by parameter 'self' outside of their declaration scope // (global, _) = local; // error 3 - Diagnostic(ErrorCode.ERR_CallArgMixing, "local").WithArguments("Extensions.Deconstruct(System.Span, out System.Span, out System.Span)", "self").WithLocation(13, 23), - // (14,9): error CS8352: Cannot use variable '(local, _) = local' in this context because it may expose referenced variables outside of their declaration scope - // (local, _) = local; - Diagnostic(ErrorCode.ERR_EscapeVariable, "(local, _) = local").WithArguments("(local, _) = local").WithLocation(14, 9), - // (14,22): error CS8350: This combination of arguments to 'Extensions.Deconstruct(Span, out Span, out Span)' is disallowed because it may expose variables referenced by parameter 'self' outside of their declaration scope - // (local, _) = local; - Diagnostic(ErrorCode.ERR_CallArgMixing, "local").WithArguments("Extensions.Deconstruct(System.Span, out System.Span, out System.Span)", "self").WithLocation(14, 22)); + Diagnostic(ErrorCode.ERR_CallArgMixing, "local").WithArguments("Extensions.Deconstruct(System.Span, out System.Span, out System.Span)", "self").WithLocation(13, 23)); } [Theory] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs index 44ac89e34c26a..85a2872f06ab6 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs @@ -5348,6 +5348,41 @@ static void M4(T t4) Diagnostic(ErrorCode.WRN_RefReturnParameter, "t4").WithArguments("t4").WithLocation(41, 26)); } + [Fact] + public void Constructors_02() + { + var source = """ + ref struct R + { + public R(ref int i) { } + public int this[R r] { get { return 0; } set { } } + } + class Program + { + static R F() + { + int i = 0; + R x = new R(ref i); + R y = default; + y = new R { [x] = 1 }; // 1 + y[x] = 1; // 2 + return y; + } + } + """; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (13,22): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope + // y = new R { [x] = 1 }; // 1 + Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(13, 22), + // (14,9): error CS8350: This combination of arguments to 'R.this[R]' is disallowed because it may expose variables referenced by parameter 'r' outside of their declaration scope + // y[x] = 1; // 2 + Diagnostic(ErrorCode.ERR_CallArgMixing, "y[x]").WithArguments("R.this[R]", "r").WithLocation(14, 9), + // (14,11): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope + // y[x] = 1; // 2 + Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(14, 11)); + } + [Fact] public void DefiniteAssignment_01() { @@ -8825,6 +8860,7 @@ static void Main() (x, (y, z1)) = s; R2 z2 = default; (x, (y, z2)) = s; // 1 + (z2, (y, z1)) = s; // 2 } static void Deconstruct(this Span s, out R2 x, out R1 y) => throw null; }"; @@ -8835,7 +8871,13 @@ static void Main() Diagnostic(ErrorCode.ERR_EscapeVariable, "(x, (y, z2)) = s").WithArguments("(x, (y, z2)) = s").WithLocation(20, 9), // (20,24): error CS8350: This combination of arguments to 'R1.Deconstruct(out R2, out R2)' is disallowed because it may expose variables referenced by parameter 'this' outside of their declaration scope // (x, (y, z2)) = s; // 1 - Diagnostic(ErrorCode.ERR_CallArgMixing, "s").WithArguments("R1.Deconstruct(out R2, out R2)", "this").WithLocation(20, 24)); + Diagnostic(ErrorCode.ERR_CallArgMixing, "s").WithArguments("R1.Deconstruct(out R2, out R2)", "this").WithLocation(20, 24), + // (21,9): error CS8352: Cannot use variable '(z2, (y, z1)) = s' in this context because it may expose referenced variables outside of their declaration scope + // (z2, (y, z1)) = s; // 2 + Diagnostic(ErrorCode.ERR_EscapeVariable, "(z2, (y, z1)) = s").WithArguments("(z2, (y, z1)) = s").WithLocation(21, 9), + // (21,25): error CS8350: This combination of arguments to 'Program.Deconstruct(Span, out R2, out R1)' is disallowed because it may expose variables referenced by parameter 's' outside of their declaration scope + // (z2, (y, z1)) = s; // 2 + Diagnostic(ErrorCode.ERR_CallArgMixing, "s").WithArguments("Program.Deconstruct(System.Span, out R2, out R1)", "s").WithLocation(21, 25)); } [Theory] @@ -9260,7 +9302,7 @@ static ref S F2(S x2) if (languageVersion == LanguageVersion.CSharp10) { comp.VerifyEmitDiagnostics( - // (8,28): error CS9063: UnscopedRefAttribute cannot be applied to this item because it is unscoped by default. + // (8,28): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. // static ref S F1([UnscopedRef] ref S x1) Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "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 @@ -10420,20 +10462,20 @@ static void F(ref R x) static void verify(CSharpCompilation comp, bool useUpdatedEscapeRules) { var parameters = comp.GetMember("A.F1").Parameters; - VerifyParameterSymbol(parameters[0], "R x1", RefKind.None, DeclarationScope.Unscoped); - VerifyParameterSymbol(parameters[1], "scoped R y1", RefKind.None, DeclarationScope.ValueScoped); + VerifyParameterSymbol(parameters[0], "R x1", RefKind.None, ScopedKind.None); + VerifyParameterSymbol(parameters[1], "scoped R y1", RefKind.None, ScopedKind.ScopedValue); parameters = comp.GetMember("A.F2").Parameters; - VerifyParameterSymbol(parameters[0], "ref R x2", RefKind.Ref, DeclarationScope.Unscoped); - VerifyParameterSymbol(parameters[1], "scoped ref R y2", RefKind.Ref, DeclarationScope.RefScoped); + VerifyParameterSymbol(parameters[0], "ref R x2", RefKind.Ref, ScopedKind.None); + VerifyParameterSymbol(parameters[1], "scoped ref R y2", RefKind.Ref, ScopedKind.ScopedRef); parameters = comp.GetMember("A.F3").Parameters; - VerifyParameterSymbol(parameters[0], "in R x3", RefKind.In, DeclarationScope.Unscoped); - VerifyParameterSymbol(parameters[1], "scoped in R y3", RefKind.In, DeclarationScope.RefScoped); + VerifyParameterSymbol(parameters[0], "in R x3", RefKind.In, ScopedKind.None); + VerifyParameterSymbol(parameters[1], "scoped in R y3", RefKind.In, ScopedKind.ScopedRef); parameters = comp.GetMember("A.F4").Parameters; - VerifyParameterSymbol(parameters[0], "out R x4", RefKind.Out, useUpdatedEscapeRules ? DeclarationScope.RefScoped : DeclarationScope.Unscoped); - VerifyParameterSymbol(parameters[1], "out R y4", RefKind.Out, DeclarationScope.RefScoped); + VerifyParameterSymbol(parameters[0], "out R x4", RefKind.Out, useUpdatedEscapeRules ? ScopedKind.ScopedRef : ScopedKind.None); + VerifyParameterSymbol(parameters[1], "out R y4", RefKind.Out, ScopedKind.ScopedRef); } } @@ -10469,8 +10511,8 @@ struct B static void verify(CSharpCompilation comp) { - VerifyParameterSymbol(comp.GetMember("A").Constructors.Single(c => !c.IsImplicitlyDeclared).Parameters[0], "scoped ref T t", RefKind.Ref, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("A.this[]").GetMethod.Parameters[0], "scoped in System.Object o", RefKind.In, DeclarationScope.RefScoped); + VerifyParameterSymbol(comp.GetMember("A").Constructors.Single(c => !c.IsImplicitlyDeclared).Parameters[0], "scoped ref T t", RefKind.Ref, ScopedKind.ScopedRef); + VerifyParameterSymbol(comp.GetMember("A.this[]").GetMethod.Parameters[0], "scoped in System.Object o", RefKind.In, ScopedKind.ScopedRef); } } @@ -10529,20 +10571,20 @@ static void verify(CSharpCompilation comp, bool useUpdatedEscapeRules) var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); var localFunctions = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol()).ToArray(); - VerifyParameterSymbol(localFunctions[0].Parameters[0], "R x1", RefKind.None, DeclarationScope.Unscoped); - VerifyParameterSymbol(localFunctions[0].Parameters[1], "scoped R y1", RefKind.None, DeclarationScope.ValueScoped); - VerifyParameterSymbol(localFunctions[1].Parameters[0], "ref System.Int32 x2", RefKind.Ref, DeclarationScope.Unscoped); - VerifyParameterSymbol(localFunctions[1].Parameters[1], "scoped ref System.Int32 y2", RefKind.Ref, DeclarationScope.RefScoped); - VerifyParameterSymbol(localFunctions[2].Parameters[0], "in System.Int32 x3", RefKind.In, DeclarationScope.Unscoped); - VerifyParameterSymbol(localFunctions[2].Parameters[1], "scoped in System.Int32 y3", RefKind.In, DeclarationScope.RefScoped); - VerifyParameterSymbol(localFunctions[3].Parameters[0], "out System.Int32 x4", RefKind.Out, useUpdatedEscapeRules ? DeclarationScope.RefScoped : DeclarationScope.Unscoped); - VerifyParameterSymbol(localFunctions[3].Parameters[1], "out System.Int32 y4", RefKind.Out, DeclarationScope.RefScoped); - VerifyParameterSymbol(localFunctions[4].Parameters[0], "ref R x5", RefKind.Ref, DeclarationScope.Unscoped); - VerifyParameterSymbol(localFunctions[4].Parameters[1], "scoped ref R y5", RefKind.Ref, DeclarationScope.RefScoped); - VerifyParameterSymbol(localFunctions[5].Parameters[0], "in R x6", RefKind.In, DeclarationScope.Unscoped); - VerifyParameterSymbol(localFunctions[5].Parameters[1], "scoped in R y6", RefKind.In, DeclarationScope.RefScoped); - VerifyParameterSymbol(localFunctions[6].Parameters[0], "out R x7", RefKind.Out, useUpdatedEscapeRules ? DeclarationScope.RefScoped : DeclarationScope.Unscoped); - VerifyParameterSymbol(localFunctions[6].Parameters[1], "out R y7", RefKind.Out, DeclarationScope.RefScoped); + VerifyParameterSymbol(localFunctions[0].Parameters[0], "R x1", RefKind.None, ScopedKind.None); + VerifyParameterSymbol(localFunctions[0].Parameters[1], "scoped R y1", RefKind.None, ScopedKind.ScopedValue); + VerifyParameterSymbol(localFunctions[1].Parameters[0], "ref System.Int32 x2", RefKind.Ref, ScopedKind.None); + VerifyParameterSymbol(localFunctions[1].Parameters[1], "scoped ref System.Int32 y2", RefKind.Ref, ScopedKind.ScopedRef); + VerifyParameterSymbol(localFunctions[2].Parameters[0], "in System.Int32 x3", RefKind.In, ScopedKind.None); + VerifyParameterSymbol(localFunctions[2].Parameters[1], "scoped in System.Int32 y3", RefKind.In, ScopedKind.ScopedRef); + VerifyParameterSymbol(localFunctions[3].Parameters[0], "out System.Int32 x4", RefKind.Out, useUpdatedEscapeRules ? ScopedKind.ScopedRef : ScopedKind.None); + VerifyParameterSymbol(localFunctions[3].Parameters[1], "out System.Int32 y4", RefKind.Out, ScopedKind.ScopedRef); + VerifyParameterSymbol(localFunctions[4].Parameters[0], "ref R x5", RefKind.Ref, ScopedKind.None); + VerifyParameterSymbol(localFunctions[4].Parameters[1], "scoped ref R y5", RefKind.Ref, ScopedKind.ScopedRef); + VerifyParameterSymbol(localFunctions[5].Parameters[0], "in R x6", RefKind.In, ScopedKind.None); + VerifyParameterSymbol(localFunctions[5].Parameters[1], "scoped in R y6", RefKind.In, ScopedKind.ScopedRef); + VerifyParameterSymbol(localFunctions[6].Parameters[0], "out R x7", RefKind.Out, useUpdatedEscapeRules ? ScopedKind.ScopedRef : ScopedKind.None); + VerifyParameterSymbol(localFunctions[6].Parameters[1], "out R y7", RefKind.Out, ScopedKind.ScopedRef); } } @@ -10558,13 +10600,13 @@ static void Main() var f1 = (R x1, scoped R y1) => { }; var f2 = (ref int x2, scoped ref int y2) => { }; var f3 = (in int x3, scoped in int y3) => { }; - var f4 = (out int x4, scoped out int y4) => { x4 = 0; y4 = 0; }; + var f4 = (out int x4, scoped out int y4, [System.Diagnostics.CodeAnalysis.UnscopedRefAttribute] out int z4) => { x4 = 0; y4 = 0; z4 = 0; }; var f5 = (ref R x5, scoped ref R y5) => { }; var f6 = (in R x6, scoped in R y6) => { }; var f7 = (out R x7, scoped out R y7) => { x7 = default; y7 = default; }; } }"; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, parseOptions: TestOptions.Regular10); comp.VerifyEmitDiagnostics( // (6,25): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. // var f1 = (R x1, scoped R y1) => { }; @@ -10576,8 +10618,11 @@ static void Main() // var f3 = (in int x3, scoped in int y3) => { }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(8, 30), // (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) => { x4 = 0; y4 = 0; }; + // 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. + // 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), // (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), @@ -10589,7 +10634,7 @@ static void Main() Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(12, 29)); verify(comp, useUpdatedEscapeRules: false); - comp = CreateCompilation(source); + comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); comp.VerifyEmitDiagnostics(); verify(comp, useUpdatedEscapeRules: true); @@ -10599,27 +10644,28 @@ 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, DeclarationScope.Unscoped); - verifyParameter(delegateTypesAndLambdas[0], 1, "scoped R", "y1", RefKind.None, DeclarationScope.ValueScoped); - verifyParameter(delegateTypesAndLambdas[1], 0, "ref System.Int32", "x2", RefKind.Ref, DeclarationScope.Unscoped); - verifyParameter(delegateTypesAndLambdas[1], 1, "scoped ref System.Int32", "y2", RefKind.Ref, DeclarationScope.RefScoped); - verifyParameter(delegateTypesAndLambdas[2], 0, "in System.Int32", "x3", RefKind.In, DeclarationScope.Unscoped); - verifyParameter(delegateTypesAndLambdas[2], 1, "scoped in System.Int32", "y3", RefKind.In, DeclarationScope.RefScoped); - verifyParameter(delegateTypesAndLambdas[3], 0, "out System.Int32", "x4", RefKind.Out, useUpdatedEscapeRules ? DeclarationScope.RefScoped : DeclarationScope.Unscoped); - verifyParameter(delegateTypesAndLambdas[3], 1, "out System.Int32", "y4", RefKind.Out, DeclarationScope.RefScoped); - verifyParameter(delegateTypesAndLambdas[4], 0, "ref R", "x5", RefKind.Ref, DeclarationScope.Unscoped); - verifyParameter(delegateTypesAndLambdas[4], 1, "scoped ref R", "y5", RefKind.Ref, DeclarationScope.RefScoped); - verifyParameter(delegateTypesAndLambdas[5], 0, "in R", "x6", RefKind.In, DeclarationScope.Unscoped); - verifyParameter(delegateTypesAndLambdas[5], 1, "scoped in R", "y6", RefKind.In, DeclarationScope.RefScoped); - verifyParameter(delegateTypesAndLambdas[6], 0, "out R", "x7", RefKind.Out, useUpdatedEscapeRules ? DeclarationScope.RefScoped : DeclarationScope.Unscoped); - verifyParameter(delegateTypesAndLambdas[6], 1, "out R", "y7", RefKind.Out, DeclarationScope.RefScoped); + 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); } - static void verifyParameter((NamedTypeSymbol, LambdaSymbol) delegateTypeAndLambda, int parameterIndex, string expectedDisplayType, string expectedDisplayName, RefKind expectedRefKind, DeclarationScope expectedScope) + static void verifyParameter((NamedTypeSymbol, LambdaSymbol) delegateTypeAndLambda, int parameterIndex, string expectedDisplayType, string expectedDisplayName, RefKind expectedRefKind, ScopedKind expectedScope, bool expectedHasUnscopedRefAttribute) { var (delegateType, lambda) = delegateTypeAndLambda; - VerifyParameterSymbol(delegateType.DelegateInvokeMethod.Parameters[parameterIndex], $"{expectedDisplayType} arg{parameterIndex + 1}", expectedRefKind, expectedScope); - VerifyParameterSymbol(lambda.Parameters[parameterIndex], $"{expectedDisplayType} {expectedDisplayName}", expectedRefKind, expectedScope); + VerifyParameterSymbol(delegateType.DelegateInvokeMethod.Parameters[parameterIndex], $"{expectedDisplayType} arg{parameterIndex + 1}", expectedRefKind, expectedScope, expectedHasUnscopedRefAttribute); + VerifyParameterSymbol(lambda.Parameters[parameterIndex], $"{expectedDisplayType} {expectedDisplayName}", expectedRefKind, expectedScope, expectedHasUnscopedRefAttribute); } static (NamedTypeSymbol, LambdaSymbol) getDelegateTypeAndLambda(SemanticModel model, VariableDeclaratorSyntax decl) @@ -10655,8 +10701,8 @@ public void ParameterScope_05() static void verify(CSharpCompilation comp, bool useUpdatedEscapeRules) { - VerifyParameterSymbol(comp.GetMember("D1").DelegateInvokeMethod.Parameters[0], "scoped R r1", RefKind.None, DeclarationScope.ValueScoped); - VerifyParameterSymbol(comp.GetMember("D2").DelegateInvokeMethod.Parameters[0], "scoped ref R r2", RefKind.Ref, DeclarationScope.RefScoped); + VerifyParameterSymbol(comp.GetMember("D1").DelegateInvokeMethod.Parameters[0], "scoped R r1", RefKind.None, ScopedKind.ScopedValue); + VerifyParameterSymbol(comp.GetMember("D2").DelegateInvokeMethod.Parameters[0], "scoped ref R r2", RefKind.Ref, ScopedKind.ScopedRef); } } @@ -10721,10 +10767,10 @@ static void verify(CSharpCompilation comp, bool useUpdatedEscapeRules) var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); var methods = decls.Select(d => ((FunctionPointerTypeSymbol)model.GetDeclaredSymbol(d).GetSymbol().Type).Signature).ToArray(); - VerifyParameterSymbol(methods[0].Parameters[0], "R", RefKind.None, DeclarationScope.Unscoped); - VerifyParameterSymbol(methods[1].Parameters[0], "ref R", RefKind.Ref, DeclarationScope.Unscoped); - VerifyParameterSymbol(methods[1].Parameters[1], "ref System.Int32", RefKind.Ref, DeclarationScope.Unscoped); - VerifyParameterSymbol(methods[2].Parameters[0], "ref R", RefKind.Ref, DeclarationScope.Unscoped); + VerifyParameterSymbol(methods[0].Parameters[0], "R", RefKind.None, ScopedKind.None); + VerifyParameterSymbol(methods[1].Parameters[0], "ref R", RefKind.Ref, ScopedKind.None); + VerifyParameterSymbol(methods[1].Parameters[1], "ref System.Int32", RefKind.Ref, ScopedKind.None); + VerifyParameterSymbol(methods[2].Parameters[0], "ref R", RefKind.Ref, ScopedKind.None); } } @@ -10743,10 +10789,10 @@ static void F6(scoped in R r) { } var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics(); - VerifyParameterSymbol(comp.GetMember("Program.F0").Parameters[0], "scoped R r", RefKind.None, DeclarationScope.ValueScoped); - VerifyParameterSymbol(comp.GetMember("Program.F3").Parameters[0], "scoped ref R r", RefKind.Ref, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("Program.F6").Parameters[0], "scoped in R r", RefKind.In, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("Program.F9").Parameters[0], "out R r", RefKind.Out, DeclarationScope.RefScoped); + VerifyParameterSymbol(comp.GetMember("Program.F0").Parameters[0], "scoped R r", RefKind.None, ScopedKind.ScopedValue); + VerifyParameterSymbol(comp.GetMember("Program.F3").Parameters[0], "scoped ref R r", RefKind.Ref, ScopedKind.ScopedRef); + VerifyParameterSymbol(comp.GetMember("Program.F6").Parameters[0], "scoped in R r", RefKind.In, ScopedKind.ScopedRef); + VerifyParameterSymbol(comp.GetMember("Program.F9").Parameters[0], "out R r", RefKind.Out, ScopedKind.ScopedRef); } [Fact] @@ -10853,14 +10899,14 @@ static void F7(scoped in scoped s) { } var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics(); - VerifyParameterSymbol(comp.GetMember("Program.F0").Parameters[0], "scoped s", RefKind.None, DeclarationScope.Unscoped); - VerifyParameterSymbol(comp.GetMember("Program.F1").Parameters[0], "scoped scoped s", RefKind.None, DeclarationScope.ValueScoped); - VerifyParameterSymbol(comp.GetMember("Program.F2").Parameters[0], "ref scoped s", RefKind.Ref, DeclarationScope.Unscoped); - VerifyParameterSymbol(comp.GetMember("Program.F4").Parameters[0], "scoped ref scoped s", RefKind.Ref, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("Program.F5").Parameters[0], "in scoped s", RefKind.In, DeclarationScope.Unscoped); - VerifyParameterSymbol(comp.GetMember("Program.F7").Parameters[0], "scoped in scoped s", RefKind.In, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("Program.F8").Parameters[0], "out scoped s", RefKind.Out, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("Program.FA").Parameters[0], "out scoped s", RefKind.Out, DeclarationScope.RefScoped); + VerifyParameterSymbol(comp.GetMember("Program.F0").Parameters[0], "scoped s", RefKind.None, ScopedKind.None); + VerifyParameterSymbol(comp.GetMember("Program.F1").Parameters[0], "scoped scoped s", RefKind.None, ScopedKind.ScopedValue); + VerifyParameterSymbol(comp.GetMember("Program.F2").Parameters[0], "ref scoped s", RefKind.Ref, ScopedKind.None); + VerifyParameterSymbol(comp.GetMember("Program.F4").Parameters[0], "scoped ref scoped s", RefKind.Ref, ScopedKind.ScopedRef); + VerifyParameterSymbol(comp.GetMember("Program.F5").Parameters[0], "in scoped s", RefKind.In, ScopedKind.None); + VerifyParameterSymbol(comp.GetMember("Program.F7").Parameters[0], "scoped in scoped s", RefKind.In, ScopedKind.ScopedRef); + VerifyParameterSymbol(comp.GetMember("Program.F8").Parameters[0], "out scoped s", RefKind.Out, ScopedKind.ScopedRef); + VerifyParameterSymbol(comp.GetMember("Program.FA").Parameters[0], "out scoped s", RefKind.Out, ScopedKind.ScopedRef); } [WorkItem(62080, "https://github.com/dotnet/roslyn/issues/62080")] @@ -10889,8 +10935,8 @@ static void Main() var model = comp.GetSemanticModel(tree); var lambdas = tree.GetRoot().DescendantNodes().OfType().Select(e => model.GetSymbolInfo(e).Symbol.GetSymbol()).ToArray(); - VerifyParameterSymbol(lambdas[0].Parameters[0], "R r1", RefKind.None, DeclarationScope.Unscoped); - VerifyParameterSymbol(lambdas[1].Parameters[0], "R r2", RefKind.None, DeclarationScope.Unscoped); + VerifyParameterSymbol(lambdas[0].Parameters[0], "R r1", RefKind.None, ScopedKind.None); + VerifyParameterSymbol(lambdas[1].Parameters[0], "R r2", RefKind.None, ScopedKind.None); } [Fact] @@ -10935,7 +10981,7 @@ static void Main() var comp = CreateCompilation(source1, references: new[] { ref0 }); comp.VerifyDiagnostics(); - VerifyParameterSymbol(comp.GetMember("A.F1").Parameters[0], "out System.Int32 i", RefKind.Out, DeclarationScope.RefScoped); + VerifyParameterSymbol(comp.GetMember("A.F1").Parameters[0], "out System.Int32 i", RefKind.Out, ScopedKind.ScopedRef); } [WorkItem(62691, "https://github.com/dotnet/roslyn/issues/62691")] @@ -10969,10 +11015,10 @@ static void Main() comp.VerifyEmitDiagnostics(); var parameters = comp.GetMember("A.F").Parameters; - VerifyParameterSymbol(parameters[0], "R a", RefKind.None, DeclarationScope.Unscoped); - VerifyParameterSymbol(parameters[1], "ref R b", RefKind.Ref, DeclarationScope.Unscoped); - VerifyParameterSymbol(parameters[2], "in R c", RefKind.In, DeclarationScope.Unscoped); - VerifyParameterSymbol(parameters[3], "out R d", RefKind.Out, DeclarationScope.RefScoped); + VerifyParameterSymbol(parameters[0], "R a", RefKind.None, ScopedKind.None); + VerifyParameterSymbol(parameters[1], "ref R b", RefKind.Ref, ScopedKind.None); + VerifyParameterSymbol(parameters[2], "in R c", RefKind.In, ScopedKind.None); + VerifyParameterSymbol(parameters[3], "out R d", RefKind.Out, ScopedKind.ScopedRef); } [WorkItem(62691, "https://github.com/dotnet/roslyn/issues/62691")] @@ -10991,25 +11037,22 @@ static ref R F1() { int i = 42; var r1 = new R(ref i); - return ref ReturnRef(ref r1); // 1 + return ref ReturnRef(ref r1); } static ref R F2(ref int i) { var r2 = new R(ref i); return ref ReturnRef(ref r2); } + + // NB: there is actually no valid implementation here except to throw. + // With this signature, we will never be able to return any ref struct by reference. static ref R ReturnRef(scoped ref R r) => throw null; }"; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); - comp.VerifyDiagnostics( - // (12,20): error CS8347: Cannot use a result of 'Program.ReturnRef(scoped ref R)' in this context because it may expose variables referenced by parameter 'r' outside of their declaration scope - // return ref ReturnRef(ref r1); // 1 - Diagnostic(ErrorCode.ERR_EscapeCall, "ReturnRef(ref r1)").WithArguments("Program.ReturnRef(scoped ref R)", "r").WithLocation(12, 20), - // (12,34): error CS8352: Cannot use variable 'r1' in this context because it may expose referenced variables outside of their declaration scope - // return ref ReturnRef(ref r1); // 1 - Diagnostic(ErrorCode.ERR_EscapeVariable, "r1").WithArguments("r1").WithLocation(12, 34)); + comp.VerifyDiagnostics(); - VerifyParameterSymbol(comp.GetMember("Program.ReturnRef").Parameters[0], "scoped ref R r", RefKind.Ref, DeclarationScope.RefScoped); + VerifyParameterSymbol(comp.GetMember("Program.ReturnRef").Parameters[0], "scoped ref R r", RefKind.Ref, ScopedKind.ScopedRef); } [Theory] @@ -11050,24 +11093,24 @@ readonly void F2() { } var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); comp.VerifyEmitDiagnostics(); - VerifyParameterSymbol(comp.GetMember("C..ctor").ThisParameter, "C this", RefKind.None, DeclarationScope.Unscoped); - VerifyParameterSymbol(comp.GetMember("C.F1").ThisParameter, "C this", RefKind.None, DeclarationScope.Unscoped); - VerifyParameterSymbol(comp.GetMember("S1..ctor").ThisParameter, "out S1 this", RefKind.Out, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("S1.F1").ThisParameter, "ref S1 this", RefKind.Ref, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("S1.F2").ThisParameter, "in S1 this", RefKind.In, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("R1..ctor").ThisParameter, "out R1 this", RefKind.Out, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("R1.F1").ThisParameter, "ref R1 this", RefKind.Ref, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("R1.F2").ThisParameter, "in R1 this", RefKind.In, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("S2..ctor").ThisParameter, "out S2 this", RefKind.Out, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("S2.F1").ThisParameter, "in S2 this", RefKind.In, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("S2.F2").ThisParameter, "in S2 this", RefKind.In, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("R2..ctor").ThisParameter, "out R2 this", RefKind.Out, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("R2.F1").ThisParameter, "in R2 this", RefKind.In, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("R2.F2").ThisParameter, "in R2 this", RefKind.In, DeclarationScope.RefScoped); + VerifyParameterSymbol(comp.GetMember("C..ctor").ThisParameter, "C this", RefKind.None, ScopedKind.None); + VerifyParameterSymbol(comp.GetMember("C.F1").ThisParameter, "C this", RefKind.None, ScopedKind.None); + VerifyParameterSymbol(comp.GetMember("S1..ctor").ThisParameter, "out S1 this", RefKind.Out, ScopedKind.ScopedRef); + VerifyParameterSymbol(comp.GetMember("S1.F1").ThisParameter, "ref S1 this", RefKind.Ref, ScopedKind.ScopedRef); + VerifyParameterSymbol(comp.GetMember("S1.F2").ThisParameter, "in S1 this", RefKind.In, ScopedKind.ScopedRef); + VerifyParameterSymbol(comp.GetMember("R1..ctor").ThisParameter, "out R1 this", RefKind.Out, ScopedKind.ScopedRef); + VerifyParameterSymbol(comp.GetMember("R1.F1").ThisParameter, "ref R1 this", RefKind.Ref, ScopedKind.ScopedRef); + VerifyParameterSymbol(comp.GetMember("R1.F2").ThisParameter, "in R1 this", RefKind.In, ScopedKind.ScopedRef); + VerifyParameterSymbol(comp.GetMember("S2..ctor").ThisParameter, "out S2 this", RefKind.Out, ScopedKind.ScopedRef); + VerifyParameterSymbol(comp.GetMember("S2.F1").ThisParameter, "in S2 this", RefKind.In, ScopedKind.ScopedRef); + VerifyParameterSymbol(comp.GetMember("S2.F2").ThisParameter, "in S2 this", RefKind.In, ScopedKind.ScopedRef); + VerifyParameterSymbol(comp.GetMember("R2..ctor").ThisParameter, "out R2 this", RefKind.Out, ScopedKind.ScopedRef); + VerifyParameterSymbol(comp.GetMember("R2.F1").ThisParameter, "in R2 this", RefKind.In, ScopedKind.ScopedRef); + VerifyParameterSymbol(comp.GetMember("R2.F2").ThisParameter, "in R2 this", RefKind.In, ScopedKind.ScopedRef); var type = comp.GetMember("S1"); var thisParameter = new ThisParameterSymbol(forMethod: null, type); // "this" parameter for property for instance. - VerifyParameterSymbol(thisParameter, "ref S1 this", RefKind.Ref, DeclarationScope.RefScoped); + VerifyParameterSymbol(thisParameter, "ref S1 this", RefKind.Ref, ScopedKind.ScopedRef); bool useUpdatedEscapeRules = languageVersion == LanguageVersion.CSharp11; Assert.Equal(useUpdatedEscapeRules, thisParameter.UseUpdatedEscapeRules); @@ -11103,10 +11146,10 @@ static void F3(this scoped ref T t) where T : struct { } Diagnostic(ErrorCode.ERR_BadThisParam, "this").WithArguments("F2").WithLocation(6, 30) ); - VerifyParameterSymbol(comp.GetMember("Extensions.F0").Parameters[0], "R r", RefKind.None, DeclarationScope.Unscoped); - VerifyParameterSymbol(comp.GetMember("Extensions.F1").Parameters[0], "scoped R r", RefKind.None, DeclarationScope.ValueScoped); - VerifyParameterSymbol(comp.GetMember("Extensions.F2").Parameters[0], "scoped", RefKind.None, DeclarationScope.Unscoped); - VerifyParameterSymbol(comp.GetMember("Extensions.F3").Parameters[0], "scoped ref T t", RefKind.Ref, DeclarationScope.RefScoped); + VerifyParameterSymbol(comp.GetMember("Extensions.F0").Parameters[0], "R r", RefKind.None, ScopedKind.None); + VerifyParameterSymbol(comp.GetMember("Extensions.F1").Parameters[0], "scoped R r", RefKind.None, ScopedKind.ScopedValue); + VerifyParameterSymbol(comp.GetMember("Extensions.F2").Parameters[0], "scoped", RefKind.None, ScopedKind.None); + VerifyParameterSymbol(comp.GetMember("Extensions.F3").Parameters[0], "scoped ref T t", RefKind.Ref, ScopedKind.ScopedRef); } [Fact] @@ -11124,7 +11167,7 @@ static void F2(params scoped object[] args) { } // static void F2(params scoped object[] args) { } Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "params scoped object[] args").WithLocation(4, 20)); - VerifyParameterSymbol(comp.GetMember("Program.F2").Parameters[0], "scoped params System.Object[] args", RefKind.None, DeclarationScope.ValueScoped); + VerifyParameterSymbol(comp.GetMember("Program.F2").Parameters[0], "scoped params System.Object[] args", RefKind.None, ScopedKind.ScopedValue); } [Theory] @@ -11380,11 +11423,11 @@ scoped R1 P3 { set { } } static void verify(CSharpCompilation comp) { - verifyValueParameter(comp.GetMember("R2.P2"), "R1 value", RefKind.None, DeclarationScope.Unscoped); - verifyValueParameter(comp.GetMember("R2.P3"), "R1 value", RefKind.None, DeclarationScope.Unscoped); + verifyValueParameter(comp.GetMember("R2.P2"), "R1 value", RefKind.None, ScopedKind.None); + verifyValueParameter(comp.GetMember("R2.P3"), "R1 value", RefKind.None, ScopedKind.None); } - static void verifyValueParameter(PropertySymbol property, string expectedDisplayString, RefKind expectedRefKind, DeclarationScope expectedScope) + static void verifyValueParameter(PropertySymbol property, string expectedDisplayString, RefKind expectedRefKind, ScopedKind expectedScope) { Assert.Equal(expectedRefKind, property.RefKind); VerifyParameterSymbol(property.SetMethod.Parameters[0], expectedDisplayString, expectedRefKind, expectedScope); @@ -11407,8 +11450,8 @@ class B : A comp.VerifyEmitDiagnostics(); var method = (MethodSymbol)comp.GetMember("B").BaseTypeNoUseSiteDiagnostics.GetMember("F"); - VerifyParameterSymbol(method.Parameters[0], "scoped R x", RefKind.None, DeclarationScope.ValueScoped); - VerifyParameterSymbol(method.Parameters[1], "scoped in System.Int32 y", RefKind.In, DeclarationScope.RefScoped); + VerifyParameterSymbol(method.Parameters[0], "scoped R x", RefKind.None, ScopedKind.ScopedValue); + VerifyParameterSymbol(method.Parameters[1], "scoped in System.Int32 y", RefKind.In, ScopedKind.ScopedRef); } [Fact] @@ -11441,15 +11484,15 @@ static void Main() var expr = tree.GetRoot().DescendantNodes().OfType().Single().Expression; var method = model.GetSymbolInfo(expr).Symbol.GetSymbol(); - VerifyParameterSymbol(method.Parameters[0], "scoped R x", RefKind.None, DeclarationScope.ValueScoped); - VerifyParameterSymbol(method.Parameters[1], "scoped in System.Int32 y", RefKind.In, DeclarationScope.RefScoped); + VerifyParameterSymbol(method.Parameters[0], "scoped R x", RefKind.None, ScopedKind.ScopedValue); + VerifyParameterSymbol(method.Parameters[1], "scoped in System.Int32 y", RefKind.In, ScopedKind.ScopedRef); } private static readonly SymbolDisplayFormat displayFormatWithScoped = SymbolDisplayFormat.TestFormat. AddParameterOptions(SymbolDisplayParameterOptions.IncludeModifiers). AddLocalOptions(SymbolDisplayLocalOptions.IncludeModifiers); - private static void VerifyParameterSymbol(ParameterSymbol parameter, string expectedDisplayString, RefKind expectedRefKind, DeclarationScope expectedScope, bool expectedHasUnscopedRefAttribute = false) + private static void VerifyParameterSymbol(ParameterSymbol parameter, string expectedDisplayString, RefKind expectedRefKind, ScopedKind expectedScope, bool expectedHasUnscopedRefAttribute = false) { Assert.Equal(expectedDisplayString, parameter.ToDisplayString(displayFormatWithScoped)); Assert.Equal(expectedRefKind, parameter.RefKind); @@ -11462,10 +11505,10 @@ private static void VerifyParameterSymbol(ParameterSymbol parameter, string expe VerifyParameterSymbol(parameter.GetPublicSymbol(), expectedDisplayString, expectedRefKind, expectedScope); } - private static void VerifyParameterSymbol(IParameterSymbol parameter, string expectedDisplayString, RefKind expectedRefKind, DeclarationScope expectedScope) + private static void VerifyParameterSymbol(IParameterSymbol parameter, string expectedDisplayString, RefKind expectedRefKind, ScopedKind expectedScope) { Assert.Equal(expectedRefKind, parameter.RefKind); - Assert.Equal(expectedScope.AsScopedKind(), parameter.ScopedKind); + Assert.Equal(expectedScope, parameter.ScopedKind); Assert.Equal(expectedDisplayString, parameter.ToDisplayString(displayFormatWithScoped)); } @@ -11521,12 +11564,12 @@ static void verify(CSharpCompilation comp) var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol()).ToArray(); - VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[1], "scoped ref R r2", RefKind.Ref, DeclarationScope.RefScoped); - VerifyLocalSymbol(locals[2], "scoped ref readonly R r5", RefKind.RefReadOnly, DeclarationScope.RefScoped); - VerifyLocalSymbol(locals[3], "scoped R r11", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[4], "scoped ref R r21", RefKind.Ref, DeclarationScope.RefScoped); - VerifyLocalSymbol(locals[5], "scoped ref readonly R r51", RefKind.RefReadOnly, DeclarationScope.RefScoped); + VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[1], "scoped ref R r2", RefKind.Ref, ScopedKind.ScopedRef); + VerifyLocalSymbol(locals[2], "scoped ref readonly R r5", RefKind.RefReadOnly, ScopedKind.ScopedRef); + VerifyLocalSymbol(locals[3], "scoped R r11", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[4], "scoped ref R r21", RefKind.Ref, ScopedKind.ScopedRef); + VerifyLocalSymbol(locals[5], "scoped ref readonly R r51", RefKind.RefReadOnly, ScopedKind.ScopedRef); foreach (var decl in decls) { @@ -11658,9 +11701,9 @@ static void verify(CSharpCompilation comp) var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol()).ToArray(); - VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[1], "scoped ref R r2", RefKind.Ref, DeclarationScope.RefScoped); - VerifyLocalSymbol(locals[2], "scoped ref readonly R r5", RefKind.RefReadOnly, DeclarationScope.RefScoped); + VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[1], "scoped ref R r2", RefKind.Ref, ScopedKind.ScopedRef); + VerifyLocalSymbol(locals[2], "scoped ref readonly R r5", RefKind.RefReadOnly, ScopedKind.ScopedRef); foreach (var decl in decls) { @@ -11844,12 +11887,12 @@ static void verify(CSharpCompilation comp) Assert.Equal(6, locals.Length); - VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[1], "scoped R r2", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[2], "scoped R r5", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[3], "scoped R r11", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[4], "scoped R r21", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[5], "scoped R r51", RefKind.None, DeclarationScope.ValueScoped); + VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[1], "scoped R r2", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[2], "scoped R r5", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[3], "scoped R r11", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[4], "scoped R r21", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[5], "scoped R r51", RefKind.None, ScopedKind.ScopedValue); foreach (var decl in decls) { @@ -12255,12 +12298,12 @@ static void verify(CSharpCompilation comp) Assert.Equal(6, locals.Length); - VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[1], "scoped R r2", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[2], "scoped R r5", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[3], "scoped R r11", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[4], "scoped R r21", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[5], "scoped R r51", RefKind.None, DeclarationScope.ValueScoped); + VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[1], "scoped R r2", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[2], "scoped R r5", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[3], "scoped R r11", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[4], "scoped R r21", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[5], "scoped R r51", RefKind.None, ScopedKind.ScopedValue); foreach (var decl in decls) { @@ -12611,12 +12654,12 @@ static void verify(CSharpCompilation comp) var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol()).ToArray(); - VerifyLocalSymbol(locals[0], "scoped s1", RefKind.None, DeclarationScope.Unscoped); - VerifyLocalSymbol(locals[1], "ref scoped s2", RefKind.Ref, DeclarationScope.Unscoped); - VerifyLocalSymbol(locals[2], "ref scoped s3", RefKind.Ref, DeclarationScope.Unscoped); - VerifyLocalSymbol(locals[3], "scoped scoped s4", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[4], "scoped ref scoped s5", RefKind.Ref, DeclarationScope.RefScoped); - VerifyLocalSymbol(locals[5], "scoped ref scoped s6", RefKind.Ref, DeclarationScope.RefScoped); + VerifyLocalSymbol(locals[0], "scoped s1", RefKind.None, ScopedKind.None); + VerifyLocalSymbol(locals[1], "ref scoped s2", RefKind.Ref, ScopedKind.None); + VerifyLocalSymbol(locals[2], "ref scoped s3", RefKind.Ref, ScopedKind.None); + VerifyLocalSymbol(locals[3], "scoped scoped s4", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[4], "scoped ref scoped s5", RefKind.Ref, ScopedKind.ScopedRef); + VerifyLocalSymbol(locals[5], "scoped ref scoped s6", RefKind.Ref, ScopedKind.ScopedRef); } } @@ -12666,12 +12709,12 @@ static void verify(CSharpCompilation comp) var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol()).ToArray(); - VerifyLocalSymbol(locals[0], "scoped s1", RefKind.None, DeclarationScope.Unscoped); - VerifyLocalSymbol(locals[1], "ref scoped s2", RefKind.Ref, DeclarationScope.Unscoped); - VerifyLocalSymbol(locals[2], "ref scoped s3", RefKind.Ref, DeclarationScope.Unscoped); - VerifyLocalSymbol(locals[3], "scoped scoped s4", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[4], "scoped ref scoped s5", RefKind.Ref, DeclarationScope.RefScoped); - VerifyLocalSymbol(locals[5], "scoped ref scoped s6", RefKind.Ref, DeclarationScope.RefScoped); + VerifyLocalSymbol(locals[0], "scoped s1", RefKind.None, ScopedKind.None); + VerifyLocalSymbol(locals[1], "ref scoped s2", RefKind.Ref, ScopedKind.None); + VerifyLocalSymbol(locals[2], "ref scoped s3", RefKind.Ref, ScopedKind.None); + VerifyLocalSymbol(locals[3], "scoped scoped s4", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[4], "scoped ref scoped s5", RefKind.Ref, ScopedKind.ScopedRef); + VerifyLocalSymbol(locals[5], "scoped ref scoped s6", RefKind.Ref, ScopedKind.ScopedRef); } } @@ -12725,10 +12768,10 @@ static void verify(CSharpCompilation comp) var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol()).ToArray(); - VerifyLocalSymbol(locals[0], "scoped s1", RefKind.None, DeclarationScope.Unscoped); - VerifyLocalSymbol(locals[2], "scoped s3", RefKind.None, DeclarationScope.Unscoped); - VerifyLocalSymbol(locals[4], "scoped scoped s4", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[6], "scoped scoped s6", RefKind.None, DeclarationScope.ValueScoped); + VerifyLocalSymbol(locals[0], "scoped s1", RefKind.None, ScopedKind.None); + VerifyLocalSymbol(locals[2], "scoped s3", RefKind.None, ScopedKind.None); + VerifyLocalSymbol(locals[4], "scoped scoped s4", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[6], "scoped scoped s6", RefKind.None, ScopedKind.ScopedValue); } } @@ -12770,10 +12813,10 @@ static void verify(CSharpCompilation comp) Assert.Equal(4, locals.Length); - VerifyLocalSymbol(locals[0], "scoped s1", RefKind.None, DeclarationScope.Unscoped); - VerifyLocalSymbol(locals[1], "scoped s3", RefKind.None, DeclarationScope.Unscoped); - VerifyLocalSymbol(locals[2], "scoped scoped s4", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[3], "scoped scoped s6", RefKind.None, DeclarationScope.ValueScoped); + VerifyLocalSymbol(locals[0], "scoped s1", RefKind.None, ScopedKind.None); + VerifyLocalSymbol(locals[1], "scoped s3", RefKind.None, ScopedKind.None); + VerifyLocalSymbol(locals[2], "scoped scoped s4", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[3], "scoped scoped s6", RefKind.None, ScopedKind.ScopedValue); } } @@ -12797,7 +12840,7 @@ public void LocalScope_05(LanguageVersion langVersion) var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol()).ToArray(); - VerifyLocalSymbol(locals[0], "System.Boolean scoped", RefKind.None, DeclarationScope.Unscoped); + VerifyLocalSymbol(locals[0], "System.Boolean scoped", RefKind.None, ScopedKind.None); } [Theory] @@ -12822,7 +12865,7 @@ public void LocalScope_05_For(LanguageVersion langVersion) var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol()).ToArray(); - VerifyLocalSymbol(locals[0], "System.Boolean scoped", RefKind.None, DeclarationScope.Unscoped); + VerifyLocalSymbol(locals[0], "System.Boolean scoped", RefKind.None, ScopedKind.None); } [Theory] @@ -12842,7 +12885,7 @@ public void LocalScope_05_Deconstruction(LanguageVersion langVersion) var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol()).ToArray(); - VerifyLocalSymbol(locals[0], "System.Boolean scoped", RefKind.None, DeclarationScope.Unscoped); + VerifyLocalSymbol(locals[0], "System.Boolean scoped", RefKind.None, ScopedKind.None); } [Theory] @@ -12864,7 +12907,7 @@ public void LocalScope_05_OutVar(LanguageVersion langVersion) var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol()).ToArray(); - VerifyLocalSymbol(locals[0], "System.Boolean scoped", RefKind.None, DeclarationScope.Unscoped); + VerifyLocalSymbol(locals[0], "System.Boolean scoped", RefKind.None, ScopedKind.None); } [Fact] @@ -12905,8 +12948,8 @@ static void verifyModel(CSharpCompilation comp) Assert.Equal("R", local.Type.ToTestDisplayString()); } - VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[1], "scoped ref R r3", RefKind.Ref, DeclarationScope.RefScoped); + VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[1], "scoped ref R r3", RefKind.Ref, ScopedKind.ScopedRef); foreach (var decl in decls) { @@ -12969,8 +13012,8 @@ static void verifyModel(CSharpCompilation comp) Assert.Equal("R", local.Type.ToTestDisplayString()); } - VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[1], "scoped ref R r3", RefKind.Ref, DeclarationScope.RefScoped); + VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[1], "scoped ref R r3", RefKind.Ref, ScopedKind.ScopedRef); foreach (var decl in decls) { @@ -13045,8 +13088,8 @@ static void verifyModel(CSharpCompilation comp) Assert.Equal("R", locals[i].Type.ToTestDisplayString()); } - VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[2], "scoped R r3", RefKind.None, DeclarationScope.ValueScoped); + VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[2], "scoped R r3", RefKind.None, ScopedKind.ScopedValue); for (int i = 0; i < 3; i += 2) { @@ -13116,8 +13159,8 @@ static void verifyModel(CSharpCompilation comp) Assert.Equal("R", local.Type.ToTestDisplayString()); } - VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[1], "scoped R r3", RefKind.None, DeclarationScope.ValueScoped); + VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[1], "scoped R r3", RefKind.None, ScopedKind.ScopedValue); foreach (var decl in decls) { @@ -13175,8 +13218,8 @@ static void Test(ref int x) var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol()).ToArray(); Assert.Equal(2, locals.Length); - VerifyLocalSymbol(locals[0], "ref System.Int32 a", RefKind.Ref, DeclarationScope.Unscoped); - VerifyLocalSymbol(locals[1], "ref System.Int32 b", RefKind.Ref, DeclarationScope.Unscoped); + VerifyLocalSymbol(locals[0], "ref System.Int32 a", RefKind.Ref, ScopedKind.None); + VerifyLocalSymbol(locals[1], "ref System.Int32 b", RefKind.Ref, ScopedKind.None); } [Fact] @@ -13815,8 +13858,8 @@ static void verify(CSharpCompilation comp, bool useUpdatedEscapeRules) var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol()).ToArray(); - VerifyLocalSymbol(locals[0], "scoped ref R r2", RefKind.Ref, DeclarationScope.RefScoped); - VerifyLocalSymbol(locals[1], "scoped ref R r5", RefKind.Ref, DeclarationScope.RefScoped); + VerifyLocalSymbol(locals[0], "scoped ref R r2", RefKind.Ref, ScopedKind.ScopedRef); + VerifyLocalSymbol(locals[1], "scoped ref R r5", RefKind.Ref, ScopedKind.ScopedRef); var type = ((VariableDeclarationSyntax)decls[0].Parent).Type; Assert.Null(model.GetTypeInfo(type).Type); @@ -13857,8 +13900,8 @@ static void verify(CSharpCompilation comp, bool useUpdatedEscapeRules) var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol()).ToArray(); - VerifyLocalSymbol(locals[0], "scoped ref R r2", RefKind.Ref, DeclarationScope.RefScoped); - VerifyLocalSymbol(locals[1], "scoped ref R r5", RefKind.Ref, DeclarationScope.RefScoped); + VerifyLocalSymbol(locals[0], "scoped ref R r2", RefKind.Ref, ScopedKind.ScopedRef); + VerifyLocalSymbol(locals[1], "scoped ref R r5", RefKind.Ref, ScopedKind.ScopedRef); var type = ((VariableDeclarationSyntax)decls[0].Parent).Type; Assert.Null(model.GetTypeInfo(type).Type); @@ -13982,19 +14025,19 @@ static void Refs(ref R r1, scoped ref R r2) var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol()).ToArray(); - VerifyLocalSymbol(locals[0], "R r11", RefKind.None, DeclarationScope.Unscoped); - VerifyLocalSymbol(locals[1], "R r12", RefKind.None, DeclarationScope.Unscoped); - VerifyLocalSymbol(locals[2], "scoped R r21", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[3], "scoped R r22", RefKind.None, DeclarationScope.ValueScoped); + VerifyLocalSymbol(locals[0], "R r11", RefKind.None, ScopedKind.None); + VerifyLocalSymbol(locals[1], "R r12", RefKind.None, ScopedKind.None); + VerifyLocalSymbol(locals[2], "scoped R r21", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[3], "scoped R r22", RefKind.None, ScopedKind.ScopedValue); - VerifyLocalSymbol(locals[4], "ref R r31", RefKind.Ref, DeclarationScope.Unscoped); - VerifyLocalSymbol(locals[5], "ref R r32", RefKind.Ref, DeclarationScope.Unscoped); - VerifyLocalSymbol(locals[6], "scoped ref R r41", RefKind.Ref, DeclarationScope.RefScoped); - VerifyLocalSymbol(locals[7], "scoped ref R r42", RefKind.Ref, DeclarationScope.RefScoped); + VerifyLocalSymbol(locals[4], "ref R r31", RefKind.Ref, ScopedKind.None); + VerifyLocalSymbol(locals[5], "ref R r32", RefKind.Ref, ScopedKind.None); + VerifyLocalSymbol(locals[6], "scoped ref R r41", RefKind.Ref, ScopedKind.ScopedRef); + VerifyLocalSymbol(locals[7], "scoped ref R r42", RefKind.Ref, ScopedKind.ScopedRef); } [Fact] - public void LocalScope_01_Foreach() + public void LocalScope_01_Foreach_01() { var source = @"#pragma warning disable 219 @@ -14058,9 +14101,9 @@ static void verify(CSharpCompilation comp) var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol()).ToArray(); - VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[1], "scoped ref R r2", RefKind.Ref, DeclarationScope.RefScoped); - VerifyLocalSymbol(locals[2], "scoped ref readonly R r5", RefKind.RefReadOnly, DeclarationScope.RefScoped); + VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[1], "scoped ref R r2", RefKind.Ref, ScopedKind.ScopedRef); + VerifyLocalSymbol(locals[2], "scoped ref readonly R r5", RefKind.RefReadOnly, ScopedKind.ScopedRef); foreach (var decl in decls) { @@ -14089,8 +14132,55 @@ static void verify(CSharpCompilation comp) } } + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void LocalScope_01_Foreach_02(LanguageVersion languageVersion) + { + var source = +@"#pragma warning disable 219 +ref struct R { } +class Program +{ + static void F(ref R r) + { + foreach (var _ in new Enumerable1()) break; + foreach (R _ in new Enumerable1()) break; + foreach (ref var _ in new Enumerable2(ref r)) break; + foreach (ref readonly var _ in new Enumerable2(ref r)) break; + foreach (ref R _ in new Enumerable2(ref r)) break; + } +} + +class Enumerable1 +{ + public Enumerator1 GetEnumerator() => default; +} + +class Enumerator1 +{ + public R Current => default; + public bool MoveNext() => false; +} + +class Enumerable2 +{ + public Enumerable2(ref R x) {} + public Enumerator2 GetEnumerator() => default; +} + +class Enumerator2 +{ + public ref R Current => throw null; + public bool MoveNext() => false; +} +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyEmitDiagnostics(); + } + [Fact] - public void LocalScope_01_Foreach_Deconstruction() + public void LocalScope_01_Foreach_Deconstruction_01() { var source = @"#pragma warning disable 219 @@ -14169,21 +14259,12 @@ class Enumerator2 // (9,52): error CS9072: A deconstruction variable cannot be declared as a ref local // foreach ((scoped ref readonly R r5, scoped ref readonly var _) in new Enumerable2(ref r)) break; Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(9, 52), - // (11,18): error CS8352: Cannot use variable '(scoped var r11, scoped R _)' in this context because it may expose referenced variables outside of their declaration scope - // foreach ((scoped var r11, scoped R _) in new Enumerable1()) break; - Diagnostic(ErrorCode.ERR_EscapeVariable, "(scoped var r11, scoped R _)").WithArguments("(scoped var r11, scoped R _)").WithLocation(11, 18), // (11,19): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. // foreach ((scoped var r11, scoped R _) in new Enumerable1()) break; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(11, 19), // (11,35): error CS9061: The 'scoped' modifier cannot be used with discard. // foreach ((scoped var r11, scoped R _) in new Enumerable1()) break; Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(11, 35), - // (11,50): error CS8350: This combination of arguments to 'R.Deconstruct(out R, out R)' is disallowed because it may expose variables referenced by parameter 'y' outside of their declaration scope - // foreach ((scoped var r11, scoped R _) in new Enumerable1()) break; - Diagnostic(ErrorCode.ERR_CallArgMixing, "new Enumerable1()").WithArguments("R.Deconstruct(out R, out R)", "y").WithLocation(11, 50), - // (12,18): error CS8352: Cannot use variable '(scoped ref var r21, scoped ref R _)' in this context because it may expose referenced variables outside of their declaration scope - // foreach ((scoped ref var r21, scoped ref R _) in new Enumerable2(ref r)) break; - Diagnostic(ErrorCode.ERR_EscapeVariable, "(scoped ref var r21, scoped ref R _)").WithArguments("(scoped ref var r21, scoped ref R _)").WithLocation(12, 18), // (12,19): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. // foreach ((scoped ref var r21, scoped ref R _) in new Enumerable2(ref r)) break; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(12, 19), @@ -14196,12 +14277,6 @@ class Enumerator2 // (12,46): error CS9072: A deconstruction variable cannot be declared as a ref local // foreach ((scoped ref var r21, scoped ref R _) in new Enumerable2(ref r)) break; Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(12, 46), - // (12,58): error CS8350: This combination of arguments to 'R.Deconstruct(out R, out R)' is disallowed because it may expose variables referenced by parameter 'y' outside of their declaration scope - // foreach ((scoped ref var r21, scoped ref R _) in new Enumerable2(ref r)) break; - Diagnostic(ErrorCode.ERR_CallArgMixing, "new Enumerable2(ref r)").WithArguments("R.Deconstruct(out R, out R)", "y").WithLocation(12, 58), - // (13,18): error CS8352: Cannot use variable '(scoped ref readonly var r51, scoped ref readonly R _)' in this context because it may expose referenced variables outside of their declaration scope - // foreach ((scoped ref readonly var r51, scoped ref readonly R _) in new Enumerable2(ref r)) break; - Diagnostic(ErrorCode.ERR_EscapeVariable, "(scoped ref readonly var r51, scoped ref readonly R _)").WithArguments("(scoped ref readonly var r51, scoped ref readonly R _)").WithLocation(13, 18), // (13,19): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. // foreach ((scoped ref readonly var r51, scoped ref readonly R _) in new Enumerable2(ref r)) break; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(13, 19), @@ -14213,12 +14288,8 @@ class Enumerator2 Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(13, 48), // (13,55): error CS9072: A deconstruction variable cannot be declared as a ref local // foreach ((scoped ref readonly var r51, scoped ref readonly R _) in new Enumerable2(ref r)) break; - Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(13, 55), - // (13,76): error CS8350: This combination of arguments to 'R.Deconstruct(out R, out R)' is disallowed because it may expose variables referenced by parameter 'y' outside of their declaration scope - // foreach ((scoped ref readonly var r51, scoped ref readonly R _) in new Enumerable2(ref r)) break; - Diagnostic(ErrorCode.ERR_CallArgMixing, "new Enumerable2(ref r)").WithArguments("R.Deconstruct(out R, out R)", "y").WithLocation(13, 76) + Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(13, 55) ); - verify(comp); comp = CreateCompilation(source); @@ -14275,12 +14346,12 @@ static void verify(CSharpCompilation comp) var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol()).ToArray(); - VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[1], "scoped R r2", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[2], "scoped R r5", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[3], "scoped R r11", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[4], "scoped R r21", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[5], "scoped R r51", RefKind.None, DeclarationScope.ValueScoped); + VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[1], "scoped R r2", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[2], "scoped R r5", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[3], "scoped R r11", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[4], "scoped R r21", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[5], "scoped R r51", RefKind.None, ScopedKind.ScopedValue); foreach (var decl in decls) { @@ -14333,6 +14404,95 @@ static void verify(CSharpCompilation comp) } } + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void LocalScope_01_Foreach_Deconstruction_02(LanguageVersion languageVersion) + { + var source = +@"#pragma warning disable 219 + +class Program +{ + static void F0(ref R r) + { + foreach ((R r0, _) in new Enumerable1()) break; + + foreach ((R r1, var _) in new Enumerable1()) break; + foreach ((ref R r2, ref var _) in new Enumerable2(ref r)) break; + foreach ((ref readonly R r5, ref readonly var _) in new Enumerable2(ref r)) break; + + foreach ((var r11, R _) in new Enumerable1()) break; + foreach ((ref var r21, ref R _) in new Enumerable2(ref r)) break; + foreach ((ref readonly var r51, ref readonly R _) in new Enumerable2(ref r)) break; + } + + static void F1() + { + var e1 = new Enumerable1().GetEnumerator(); + e1.MoveNext(); + e1.Current.Deconstruct(out R r0, out _); + e1.Current.Deconstruct(out R r1, out var _); + e1.Current.Deconstruct(out var r11, out R _); + } +} + +ref struct R +{ + public void Deconstruct(out R x, out R y) => throw null; +} + +class Enumerable1 +{ + public Enumerator1 GetEnumerator() => default; +} + +class Enumerator1 +{ + public R Current => default; + public bool MoveNext() => false; +} + +class Enumerable2 +{ + public Enumerable2(ref R x) {} + public Enumerator2 GetEnumerator() => default; +} + +class Enumerator2 +{ + public ref R Current => throw null; + public bool MoveNext() => false; +} +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyEmitDiagnostics( + // (10,19): error CS9072: A deconstruction variable cannot be declared as a ref local + // foreach ((ref R r2, ref var _) in new Enumerable2(ref r)) break; + Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(10, 19), + // (10,29): error CS9072: A deconstruction variable cannot be declared as a ref local + // foreach ((ref R r2, ref var _) in new Enumerable2(ref r)) break; + Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(10, 29), + // (11,19): error CS9072: A deconstruction variable cannot be declared as a ref local + // foreach ((ref readonly R r5, ref readonly var _) in new Enumerable2(ref r)) break; + Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(11, 19), + // (11,38): error CS9072: A deconstruction variable cannot be declared as a ref local + // foreach ((ref readonly R r5, ref readonly var _) in new Enumerable2(ref r)) break; + Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(11, 38), + // (14,19): error CS9072: A deconstruction variable cannot be declared as a ref local + // foreach ((ref var r21, ref R _) in new Enumerable2(ref r)) break; + Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(14, 19), + // (14,32): error CS9072: A deconstruction variable cannot be declared as a ref local + // foreach ((ref var r21, ref R _) in new Enumerable2(ref r)) break; + Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(14, 32), + // (15,19): error CS9072: A deconstruction variable cannot be declared as a ref local + // foreach ((ref readonly var r51, ref readonly R _) in new Enumerable2(ref r)) break; + Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(15, 19), + // (15,41): error CS9072: A deconstruction variable cannot be declared as a ref local + // foreach ((ref readonly var r51, ref readonly R _) in new Enumerable2(ref r)) break; + Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(15, 41)); + } + [Fact] public void LocalScope_04_Foreach() { @@ -14394,12 +14554,12 @@ static void verify(CSharpCompilation comp) var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol()).ToArray(); - VerifyLocalSymbol(locals[0], "scoped s1", RefKind.None, DeclarationScope.Unscoped); - VerifyLocalSymbol(locals[1], "ref scoped s2", RefKind.Ref, DeclarationScope.Unscoped); - VerifyLocalSymbol(locals[2], "ref scoped s3", RefKind.Ref, DeclarationScope.Unscoped); - VerifyLocalSymbol(locals[3], "scoped scoped s4", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[4], "scoped ref scoped s5", RefKind.Ref, DeclarationScope.RefScoped); - VerifyLocalSymbol(locals[5], "scoped ref scoped s6", RefKind.Ref, DeclarationScope.RefScoped); + VerifyLocalSymbol(locals[0], "scoped s1", RefKind.None, ScopedKind.None); + VerifyLocalSymbol(locals[1], "ref scoped s2", RefKind.Ref, ScopedKind.None); + VerifyLocalSymbol(locals[2], "ref scoped s3", RefKind.Ref, ScopedKind.None); + VerifyLocalSymbol(locals[3], "scoped scoped s4", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[4], "scoped ref scoped s5", RefKind.Ref, ScopedKind.ScopedRef); + VerifyLocalSymbol(locals[5], "scoped ref scoped s6", RefKind.Ref, ScopedKind.ScopedRef); } } @@ -14420,7 +14580,7 @@ public void LocalScope_05_Foreach(LanguageVersion langVersion) var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol()).ToArray(); - VerifyLocalSymbol(locals[0], "System.Boolean scoped", RefKind.None, DeclarationScope.Unscoped); + VerifyLocalSymbol(locals[0], "System.Boolean scoped", RefKind.None, ScopedKind.None); } [Fact] @@ -14481,8 +14641,8 @@ static void verifyModel(CSharpCompilation comp) Assert.Equal("R", local.Type.ToTestDisplayString()); } - VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[1], "scoped ref R r3", RefKind.Ref, DeclarationScope.RefScoped); + VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[1], "scoped ref R r3", RefKind.Ref, ScopedKind.ScopedRef); foreach (var decl in decls) { @@ -15052,7 +15212,7 @@ class Enumerator1 ); } - private static void VerifyLocalSymbol(LocalSymbol local, string expectedDisplayString, RefKind expectedRefKind, DeclarationScope expectedScope) + private static void VerifyLocalSymbol(LocalSymbol local, string expectedDisplayString, RefKind expectedRefKind, ScopedKind expectedScope) { Assert.Equal(expectedRefKind, local.RefKind); Assert.Equal(expectedScope, local.Scope); @@ -15061,10 +15221,10 @@ private static void VerifyLocalSymbol(LocalSymbol local, string expectedDisplayS VerifyLocalSymbol(local.GetPublicSymbol(), expectedDisplayString, expectedRefKind, expectedScope); } - private static void VerifyLocalSymbol(ILocalSymbol local, string expectedDisplayString, RefKind expectedRefKind, DeclarationScope expectedScope) + private static void VerifyLocalSymbol(ILocalSymbol local, string expectedDisplayString, RefKind expectedRefKind, ScopedKind expectedScope) { Assert.Equal(expectedRefKind, local.RefKind); - Assert.Equal(expectedScope.AsScopedKind(), local.ScopedKind); + Assert.Equal(expectedScope, local.ScopedKind); Assert.Equal(expectedDisplayString, local.ToDisplayString(displayFormatWithScoped)); } @@ -15101,7 +15261,7 @@ static void Main() { var method = module.GlobalNamespace.GetMember("I.M"); // Attribute is not included for the parameter from the embedded method. - VerifyParameterSymbol(method.Parameters[0], "ref System.Int32 i", RefKind.Ref, DeclarationScope.Unscoped); + VerifyParameterSymbol(method.Parameters[0], "ref System.Int32 i", RefKind.Ref, ScopedKind.None); }); } @@ -15877,7 +16037,10 @@ void M2(D2 d2) { } // (13,9): error CS0121: The call is ambiguous between the following methods or properties: 'C.M2(D1)' and 'C.M2(D2)' // M2(r => r); // 1 Diagnostic(ErrorCode.ERR_AmbigCall, "M2").WithArguments("C.M2(D1)", "C.M2(D2)").WithLocation(13, 9), - // (14,28): error CS8352: Cannot use variable 'scoped R r' in this context because it may expose referenced variables outside of their declaration scope + // (14,9): error CS0121: The call is ambiguous between the following methods or properties: 'C.M2(D1)' and 'C.M2(D2)' + // M2((scoped R r) => r); // 2 + Diagnostic(ErrorCode.ERR_AmbigCall, "M2").WithArguments("C.M2(D1)", "C.M2(D2)").WithLocation(14, 9), + // (14,28): error CS8352: Cannot use variable 'scoped R' in this context because it may expose referenced variables outside of their declaration scope // M2((scoped R r) => r); // 2 Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("scoped R r").WithLocation(14, 28), // (15,9): error CS0121: The call is ambiguous between the following methods or properties: 'C.M2(D1)' and 'C.M2(D2)' @@ -16176,12 +16339,88 @@ static void M(D2 d2) { } // (18,36): error CS8352: Cannot use variable 'scoped R r8' in this context because it may expose referenced variables outside of their declaration scope // D1 d1_3 = (scoped R r8) => r8; // 7 Diagnostic(ErrorCode.ERR_EscapeVariable, "r8").WithArguments("scoped R r8").WithLocation(18, 36), + // (19,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M(D1)' and 'Program.M(D2)' + // M((scoped R r9) => r9); // 8 + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("Program.M(D1)", "Program.M(D2)").WithLocation(19, 9), // (19,28): error CS8352: Cannot use variable 'scoped R r9' in this context because it may expose referenced variables outside of their declaration scope // M((scoped R r9) => r9); // 8 Diagnostic(ErrorCode.ERR_EscapeVariable, "r9").WithArguments("scoped R r9").WithLocation(19, 28) ); } + [Fact] + public void DelegateConversions_13() + { + var source = """ + ref struct R { } + + delegate R D1(R r); + delegate object D2(object o); + + class Program + { + static void M(D1 d1) { } + static void M(D2 d2) { } + + static R F(R r, ref int i) => r; + static object F(object o, ref int i) => o; + + static void Main() + { + M(x => + { + int i = 0; + return F(x, ref i); + }); + } + } + """; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (16,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M(D1)' and 'Program.M(D2)' + // M(x => + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("Program.M(D1)", "Program.M(D2)").WithLocation(16, 9)); + } + + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void DelegateConversions_14(LanguageVersion languageVersion) + { + var source = """ + using System; + + ref struct R { } + + delegate R D1(R r); + delegate object D2(object o); + + class Program + { + static void M(D1 d1) { } + static void M(D2 d2) { } + + static void F(ref R x, ref Span y) { } + static void F(ref object x, ref Span y) { } + + static void Main() + { + M(x => + { + Span y = stackalloc int[1]; + F(ref x, ref y); + return x; + }); + } + } + """; + var comp = CreateCompilationWithSpan(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyDiagnostics( + // (18,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M(D1)' and 'Program.M(D2)' + // M(x => + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("Program.M(D1)", "Program.M(D2)").WithLocation(18, 9)); + } + [Fact] public void FunctionPointerConversions() { @@ -17155,9 +17394,9 @@ static void F3(ref int x3, scoped ref int y3) var decls = tree.GetRoot().DescendantNodes().OfType().Where(v => v.Identifier.Text == "f").ToArray(); var delegateInvokeMethods = decls.Select(d => ((ILocalSymbol)model.GetDeclaredSymbol(d)).Type.GetSymbol().DelegateInvokeMethod).ToArray(); - VerifyParameterSymbol(delegateInvokeMethods[0].Parameters[0], "R arg1", RefKind.None, DeclarationScope.Unscoped); - VerifyParameterSymbol(delegateInvokeMethods[0].Parameters[1], "scoped R arg2", RefKind.None, DeclarationScope.ValueScoped); - VerifyParameterSymbol(delegateInvokeMethods[1].Parameters[1], "scoped ref System.Int32 arg2", RefKind.Ref, DeclarationScope.RefScoped); + VerifyParameterSymbol(delegateInvokeMethods[0].Parameters[0], "R arg1", RefKind.None, ScopedKind.None); + VerifyParameterSymbol(delegateInvokeMethods[0].Parameters[1], "scoped R arg2", RefKind.None, ScopedKind.ScopedValue); + VerifyParameterSymbol(delegateInvokeMethods[1].Parameters[1], "scoped ref System.Int32 arg2", RefKind.Ref, ScopedKind.ScopedRef); } [Fact] @@ -19865,8 +20104,6 @@ ref struct R2 public ref int _f; } "; - // Diagnostic is missing parameter name - // Tracked by https://github.com/dotnet/roslyn/issues/62096 var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); comp.VerifyDiagnostics( // (7,31): error CS8331: Cannot assign to variable 'i' or use it as the right hand side of a ref assignment because it is a readonly variable @@ -21767,12 +22004,12 @@ object P6 }"; var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition, IsExternalInitTypeDefinition }); comp.VerifyDiagnostics( - // (6,6): error CS9063: UnscopedRefAttribute cannot be applied to this item because it is unscoped by default. + // (6,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] object P3 { get; init; } // 1 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(6, 6), - // (15,10): error CS9063: UnscopedRefAttribute cannot be applied to this item because it is unscoped by default. + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(6, 6), + // (15,10): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] init; // 2 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(15, 10)); + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(15, 10)); } [Theory] @@ -21870,14 +22107,131 @@ R this[int i] // (11,16): error CS8374: Cannot ref-assign 'this' to 'F' because 'this' has a narrower escape scope than 'F'. // init { value.F = ref this; } // 1 Diagnostic(ErrorCode.ERR_RefAssignNarrower, "value.F = ref this").WithArguments("F", "this").WithLocation(11, 16), - // (19,10): error CS9063: UnscopedRefAttribute cannot be applied to this item because it is unscoped by default. + // (19,10): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(19, 10), + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(19, 10), // (20,16): error CS8374: Cannot ref-assign 'this' to 'F' because 'this' has a narrower escape scope than 'F'. // init { value.F = ref this; } // 2 Diagnostic(ErrorCode.ERR_RefAssignNarrower, "value.F = ref this").WithArguments("F", "this").WithLocation(20, 16)); } + [ConditionalFact(typeof(CoreClrOnly))] + public void UnscopedRefAttribute_Event_01() + { + var source = +@"#pragma warning disable 67 +using System.Diagnostics.CodeAnalysis; +delegate void D(); +class C +{ + [UnscopedRef] event D E1; // 1 + [UnscopedRef] event D E2 { add { } remove { } } // 2 +} +struct S +{ + [UnscopedRef] event D E3; // 3 + [UnscopedRef] event D E4 { add { } remove { } } // 4 +} +interface I +{ + [UnscopedRef] event D E5; // 5 + [UnscopedRef] event D E6 { add { } remove { } } // 6 +}"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, targetFramework: TargetFramework.Net60); + comp.VerifyDiagnostics( + // (6,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] event D E1; // 1 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(6, 6), + // (7,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] event D E2 { add { } remove { } } // 2 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(7, 6), + // (11,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] event D E3; // 3 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(11, 6), + // (12,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] event D E4 { add { } remove { } } // 4 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(12, 6), + // (16,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] event D E5; // 5 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(16, 6), + // (17,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] event D E6 { add { } remove { } } // 6 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(17, 6)); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public void UnscopedRefAttribute_Event_02() + { + var source = +@"#pragma warning disable 67 +using System.Diagnostics.CodeAnalysis; +delegate void D(); +class C +{ + event D E1 { [UnscopedRef] add { } remove { } } // 1 + event D E2 { add { } [UnscopedRef] remove { } } // 2 +} +struct S +{ + event D E3 { [UnscopedRef] add { } remove { } } // 3 + event D E4 { add { } [UnscopedRef] remove { } } // 4 +} +interface I +{ + event D E5 { [UnscopedRef] add { } remove { } } // 5 + event D E6 { add { } [UnscopedRef] remove { } } // 6 +} +"; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyDiagnostics( + // (6,19): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // event D E1 { [UnscopedRef] add { } remove { } } // 1 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(6, 19), + // (7,27): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // event D E2 { add { } [UnscopedRef] remove { } } // 2 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(7, 27), + // (11,19): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // event D E3 { [UnscopedRef] add { } remove { } } // 3 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(11, 19), + // (12,27): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // event D E4 { add { } [UnscopedRef] remove { } } // 4 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(12, 27), + // (16,19): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // event D E5 { [UnscopedRef] add { } remove { } } // 5 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(16, 19), + // (17,27): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // event D E6 { add { } [UnscopedRef] remove { } } // 6 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(17, 27)); + } + + [Theory] + [InlineData("class")] + [InlineData("struct")] + [InlineData("ref struct")] + public void UnscopedRefAttribute_Method_05(string type) + { + var source = +$@"using System.Diagnostics.CodeAnalysis; +{type} C +{{ + void F() + {{ + var d = [UnscopedRef] (ref int i) => ref i; + [UnscopedRef] ref int Local() => throw null; + Local(); + }} +}} +"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics( + // (6,18): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // var d = [UnscopedRef] (ref int i) => ref i; + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(6, 18), + // (7,10): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] ref int Local() => throw null; + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(7, 10)); + } + [Theory] [CombinatorialData] public void UnscopedRefAttribute_SubstitutedMembers(bool useCompilationReference) @@ -21935,13 +22289,13 @@ static ref int F2(bool b) var type = types[0]; Assert.Equal("R1", type.ToTestDisplayString()); - VerifyParameterSymbol(type.GetMethod("Get").ThisParameter, "ref R1 this", RefKind.Ref, DeclarationScope.RefScoped, expectedHasUnscopedRefAttribute: false); - VerifyParameterSymbol(type.GetMethod("get_Item").ThisParameter, "ref R1 this", RefKind.Ref, DeclarationScope.RefScoped, expectedHasUnscopedRefAttribute: false); + VerifyParameterSymbol(type.GetMethod("Get").ThisParameter, "ref R1 this", RefKind.Ref, ScopedKind.ScopedRef, expectedHasUnscopedRefAttribute: false); + VerifyParameterSymbol(type.GetMethod("get_Item").ThisParameter, "ref R1 this", RefKind.Ref, ScopedKind.ScopedRef, expectedHasUnscopedRefAttribute: false); type = types[1]; Assert.Equal("R2", type.ToTestDisplayString()); - VerifyParameterSymbol(type.GetMethod("Get").ThisParameter, "ref R2 this", RefKind.Ref, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); - VerifyParameterSymbol(type.GetMethod("get_Item").ThisParameter, "ref R2 this", RefKind.Ref, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); + VerifyParameterSymbol(type.GetMethod("Get").ThisParameter, "ref R2 this", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: true); + VerifyParameterSymbol(type.GetMethod("get_Item").ThisParameter, "ref R2 this", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: true); } [Fact] @@ -22004,14 +22358,14 @@ static ref readonly int F2(bool b) var type = types[0]; var underlyingType = (RetargetingNamedTypeSymbol)type.OriginalDefinition; Assert.Equal("R1", type.ToTestDisplayString()); - VerifyParameterSymbol(type.GetMethod("Get").ThisParameter, "ref R1 this", RefKind.Ref, DeclarationScope.RefScoped, expectedHasUnscopedRefAttribute: false); - VerifyParameterSymbol(type.GetMethod("get_Item").ThisParameter, "ref R1 this", RefKind.Ref, DeclarationScope.RefScoped, expectedHasUnscopedRefAttribute: false); + VerifyParameterSymbol(type.GetMethod("Get").ThisParameter, "ref R1 this", RefKind.Ref, ScopedKind.ScopedRef, expectedHasUnscopedRefAttribute: false); + VerifyParameterSymbol(type.GetMethod("get_Item").ThisParameter, "ref R1 this", RefKind.Ref, ScopedKind.ScopedRef, expectedHasUnscopedRefAttribute: false); type = types[1]; underlyingType = (RetargetingNamedTypeSymbol)type.OriginalDefinition; Assert.Equal("R2", type.ToTestDisplayString()); - VerifyParameterSymbol(type.GetMethod("Get").ThisParameter, "ref R2 this", RefKind.Ref, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); - VerifyParameterSymbol(type.GetMethod("get_Item").ThisParameter, "ref R2 this", RefKind.Ref, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); + VerifyParameterSymbol(type.GetMethod("Get").ThisParameter, "ref R2 this", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: true); + VerifyParameterSymbol(type.GetMethod("get_Item").ThisParameter, "ref R2 this", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: true); } [Fact] @@ -22049,6 +22403,38 @@ struct B // (18,9): error CS8374: Cannot ref-assign 'this' to 'F' because 'this' has a narrower escape scope than 'F'. // r.F = ref this; // 2 Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r.F = ref this").WithArguments("F", "this").WithLocation(18, 9)); + + // With UnscopedRefAttribute definition that allows use on constructors. + comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, targetFramework: TargetFramework.Net70); + comp.VerifyDiagnostics( + // (10,9): error CS8374: Cannot ref-assign 'this' to 'F' because 'this' has a narrower escape scope than 'F'. + // r.F = ref this; // 1 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r.F = ref this").WithArguments("F", "this").WithLocation(10, 9), + // (15,6): warning CS0436: The type 'UnscopedRefAttribute' in '' conflicts with the imported type 'UnscopedRefAttribute' in 'System.Runtime, Version=7.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. Using the type defined in ''. + // [UnscopedRef] + Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "UnscopedRef").WithArguments("", "System.Diagnostics.CodeAnalysis.UnscopedRefAttribute", "System.Runtime, Version=7.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Diagnostics.CodeAnalysis.UnscopedRefAttribute").WithLocation(15, 6), + // (15,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(15, 6), + // (18,9): error CS8374: Cannot ref-assign 'this' to 'F' because 'this' has a narrower escape scope than 'F'. + // r.F = ref this; // 2 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r.F = ref this").WithArguments("F", "this").WithLocation(18, 9)); + } + + [Fact] + public void UnscopedRefAttribute_Destructor() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +class C +{ + [UnscopedRef] ~C() { } +}"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics( + // (4,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] ~C() { } + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(4, 6)); } [Fact] @@ -22064,15 +22450,15 @@ [UnscopedRef] static S() { } // 1 }"; var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); comp.VerifyDiagnostics( - // (4,6): error CS9063: UnscopedRefAttribute cannot be applied to this item because it is unscoped by default. + // (4,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] static S() { } // 1 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(4, 6), - // (5,6): error CS9063: UnscopedRefAttribute cannot be applied to this item because it is unscoped by default. + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(4, 6), + // (5,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] static object F() => null; // 2 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(5, 6), - // (6,6): error CS9063: UnscopedRefAttribute cannot be applied to this item because it is unscoped by default. + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(5, 6), + // (6,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] static object P => null; // 3 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(6, 6)); + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(6, 6)); } [Fact] @@ -22094,12 +22480,12 @@ record struct S }"; var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); comp.VerifyDiagnostics( - // (4,6): error CS9063: UnscopedRefAttribute cannot be applied to this item because it is unscoped by default. + // (4,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] object F1() => null; // 1 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(4, 6), - // (8,6): error CS9063: UnscopedRefAttribute cannot be applied to this item because it is unscoped by default. + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(4, 6), + // (8,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] object F2() => null; // 2 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(8, 6)); + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(8, 6)); } [WorkItem(62691, "https://github.com/dotnet/roslyn/issues/62691")] @@ -22126,8 +22512,8 @@ static ref R ReturnRefStructRef(bool b, scoped ref R x, ref R y) Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "x").WithArguments("x").WithLocation(8, 24)); var parameters = comp.GetMember("Program.ReturnRefStructRef").Parameters; - VerifyParameterSymbol(parameters[1], "scoped ref R x", RefKind.Ref, DeclarationScope.RefScoped); - VerifyParameterSymbol(parameters[2], "ref R y", RefKind.Ref, DeclarationScope.Unscoped); + VerifyParameterSymbol(parameters[1], "scoped ref R x", RefKind.Ref, ScopedKind.ScopedRef); + VerifyParameterSymbol(parameters[2], "ref R y", RefKind.Ref, ScopedKind.None); } [CombinatorialData] @@ -22189,8 +22575,8 @@ ref int F2B() ); var baseType = comp.GetMember("B1").BaseTypeNoUseSiteDiagnostics; - VerifyParameterSymbol(baseType.GetMethod("F1A").Parameters[0], "ref R r1", RefKind.Ref, DeclarationScope.Unscoped); - VerifyParameterSymbol(baseType.GetMethod("F2A").Parameters[0], "scoped ref R r2", RefKind.Ref, DeclarationScope.RefScoped); + VerifyParameterSymbol(baseType.GetMethod("F1A").Parameters[0], "ref R r1", RefKind.Ref, ScopedKind.None); + VerifyParameterSymbol(baseType.GetMethod("F2A").Parameters[0], "scoped ref R r2", RefKind.Ref, ScopedKind.ScopedRef); var sourceB2 = @"class B2 : A @@ -22273,15 +22659,15 @@ public ref T F4([UnscopedRef] scoped R t4) // 4 // (18,22): error CS9066: UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. // public ref T F3([UnscopedRef] scoped in R t3) // 3 Diagnostic(ErrorCode.ERR_UnscopedScoped, "UnscopedRef").WithLocation(18, 22), - // (22,22): error CS9063: UnscopedRefAttribute cannot be applied to this item because it is unscoped by default. + // (22,22): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. // public ref T F4([UnscopedRef] scoped R t4) // 4 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(22, 22)); var type = comp.GetMember("A"); - VerifyParameterSymbol(type.GetMethod("F1").Parameters[0], "ref R r1", RefKind.Ref, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); - VerifyParameterSymbol(type.GetMethod("F2").Parameters[0], "out T t2", RefKind.Out, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); - VerifyParameterSymbol(type.GetMethod("F3").Parameters[0], "in R t3", RefKind.In, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); - VerifyParameterSymbol(type.GetMethod("F4").Parameters[0], "R t4", RefKind.None, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); + VerifyParameterSymbol(type.GetMethod("F1").Parameters[0], "ref R r1", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: true); + VerifyParameterSymbol(type.GetMethod("F2").Parameters[0], "out T t2", RefKind.Out, ScopedKind.None, expectedHasUnscopedRefAttribute: true); + VerifyParameterSymbol(type.GetMethod("F3").Parameters[0], "in R t3", RefKind.In, ScopedKind.None, expectedHasUnscopedRefAttribute: true); + VerifyParameterSymbol(type.GetMethod("F4").Parameters[0], "R t4", RefKind.None, ScopedKind.None, expectedHasUnscopedRefAttribute: true); } [Fact, WorkItem(63070, "https://github.com/dotnet/roslyn/issues/63070")] @@ -22362,7 +22748,31 @@ ref int F4B() Diagnostic(ErrorCode.ERR_BindToBogus, "F4A").WithArguments("A.F4A(ref R)").WithLocation(7, 20)); var baseType = comp.GetMember("B").BaseTypeNoUseSiteDiagnostics; - VerifyParameterSymbol(baseType.GetMethod("F4A").Parameters[0], "ref R r4", RefKind.Ref, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); + VerifyParameterSymbol(baseType.GetMethod("F4A").Parameters[0], "ref R r4", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: true); + } + + [Fact] + public void UnscopedRefAttribute_Parameter_01() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +class Program +{ + static void F([UnscopedRef] int x, [UnscopedRef] object y) { } +} +"; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyDiagnostics( + // (4,20): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. + // static void F([UnscopedRef] int x, [UnscopedRef] object y) { } + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(4, 20), + // (4,41): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. + // static void F([UnscopedRef] int x, [UnscopedRef] object y) { } + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(4, 41)); + + var parameters = comp.GetMember("Program.F").Parameters; + VerifyParameterSymbol(parameters[0], "System.Int32 x", RefKind.None, default, expectedHasUnscopedRefAttribute: true); + VerifyParameterSymbol(parameters[1], "System.Object y", RefKind.None, default, expectedHasUnscopedRefAttribute: true); } [Fact] @@ -22389,8 +22799,8 @@ static ref int ReturnOut(bool b, out int x, [UnscopedRef] out int y) Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "x").WithArguments("x").WithLocation(9, 24)); var parameters = comp.GetMember("Program.ReturnOut").Parameters; - VerifyParameterSymbol(parameters[1], "out System.Int32 x", RefKind.Out, DeclarationScope.RefScoped, expectedHasUnscopedRefAttribute: false); - VerifyParameterSymbol(parameters[2], "out System.Int32 y", RefKind.Out, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); + VerifyParameterSymbol(parameters[1], "out System.Int32 x", RefKind.Out, ScopedKind.ScopedRef, expectedHasUnscopedRefAttribute: false); + VerifyParameterSymbol(parameters[2], "out System.Int32 y", RefKind.Out, ScopedKind.None, expectedHasUnscopedRefAttribute: true); } [CombinatorialData] @@ -22448,9 +22858,9 @@ ref int F3B() Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(16, 28)); var baseType = comp.GetMember("B").BaseTypeNoUseSiteDiagnostics; - VerifyParameterSymbol(baseType.GetMethod("F1A").Parameters[0], "out System.Int32 t1", RefKind.Out, DeclarationScope.RefScoped, expectedHasUnscopedRefAttribute: false); - VerifyParameterSymbol(baseType.GetMethod("F2A").Parameters[0], "out System.Int32 t2", RefKind.Out, DeclarationScope.RefScoped, expectedHasUnscopedRefAttribute: false); - VerifyParameterSymbol(baseType.GetMethod("F3A").Parameters[0], "out System.Int32 t3", RefKind.Out, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); + VerifyParameterSymbol(baseType.GetMethod("F1A").Parameters[0], "out System.Int32 t1", RefKind.Out, ScopedKind.ScopedRef, expectedHasUnscopedRefAttribute: false); + VerifyParameterSymbol(baseType.GetMethod("F2A").Parameters[0], "out System.Int32 t2", RefKind.Out, ScopedKind.ScopedRef, expectedHasUnscopedRefAttribute: false); + VerifyParameterSymbol(baseType.GetMethod("F3A").Parameters[0], "out System.Int32 t3", RefKind.Out, ScopedKind.None, expectedHasUnscopedRefAttribute: true); } [Fact] @@ -22513,10 +22923,10 @@ ref int F4B() Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(29, 28)); var baseType = comp.GetMember("B").BaseTypeNoUseSiteDiagnostics; - VerifyParameterSymbol(baseType.GetMethod("F1A").Parameters[0], "ref System.Int32 t1", RefKind.Ref, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: false); - VerifyParameterSymbol(baseType.GetMethod("F2A").Parameters[0], "scoped ref System.Int32 t2", RefKind.Ref, DeclarationScope.RefScoped, expectedHasUnscopedRefAttribute: false); - VerifyParameterSymbol(baseType.GetMethod("F3A").Parameters[0], "ref System.Int32 t3", RefKind.Ref, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); - VerifyParameterSymbol(baseType.GetMethod("F4A").Parameters[0], "ref System.Int32 t4", RefKind.Ref, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); + VerifyParameterSymbol(baseType.GetMethod("F1A").Parameters[0], "ref System.Int32 t1", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: false); + VerifyParameterSymbol(baseType.GetMethod("F2A").Parameters[0], "scoped ref System.Int32 t2", RefKind.Ref, ScopedKind.ScopedRef, expectedHasUnscopedRefAttribute: false); + VerifyParameterSymbol(baseType.GetMethod("F3A").Parameters[0], "ref System.Int32 t3", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: true); + VerifyParameterSymbol(baseType.GetMethod("F4A").Parameters[0], "ref System.Int32 t4", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: true); } [Fact] @@ -22579,10 +22989,10 @@ ref readonly int F4B() Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(29, 27)); var baseType = comp.GetMember("B").BaseTypeNoUseSiteDiagnostics; - VerifyParameterSymbol(baseType.GetMethod("F1A").Parameters[0], "in System.Int32 t1", RefKind.In, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: false); - VerifyParameterSymbol(baseType.GetMethod("F2A").Parameters[0], "scoped in System.Int32 t2", RefKind.In, DeclarationScope.RefScoped, expectedHasUnscopedRefAttribute: false); - VerifyParameterSymbol(baseType.GetMethod("F3A").Parameters[0], "in System.Int32 t3", RefKind.In, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); - VerifyParameterSymbol(baseType.GetMethod("F4A").Parameters[0], "in System.Int32 t4", RefKind.In, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); + VerifyParameterSymbol(baseType.GetMethod("F1A").Parameters[0], "in System.Int32 t1", RefKind.In, ScopedKind.None, expectedHasUnscopedRefAttribute: false); + VerifyParameterSymbol(baseType.GetMethod("F2A").Parameters[0], "scoped in System.Int32 t2", RefKind.In, ScopedKind.ScopedRef, expectedHasUnscopedRefAttribute: false); + VerifyParameterSymbol(baseType.GetMethod("F3A").Parameters[0], "in System.Int32 t3", RefKind.In, ScopedKind.None, expectedHasUnscopedRefAttribute: true); + VerifyParameterSymbol(baseType.GetMethod("F4A").Parameters[0], "in System.Int32 t4", RefKind.In, ScopedKind.None, expectedHasUnscopedRefAttribute: true); } [Fact] @@ -22643,10 +23053,10 @@ ref int F4B() }"; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics( - // (17,23): error CS9063: UnscopedRefAttribute cannot be applied to this item because it is unscoped by default. + // (17,23): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. // public ref T F3A([UnscopedRef] R r3) Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(17, 23), - // (21,23): error CS9063: UnscopedRefAttribute cannot be applied to this item because it is unscoped by default. + // (21,23): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. // public ref T F4A([UnscopedRef] scoped R r4) Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(21, 23), // (32,20): error CS8347: Cannot use a result of 'A.F1A(R)' in this context because it may expose variables referenced by parameter 'r1' outside of their declaration scope @@ -22669,10 +23079,10 @@ ref int F4B() Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(50, 24)); var baseType = comp.GetMember("B").BaseTypeNoUseSiteDiagnostics; - VerifyParameterSymbol(baseType.GetMethod("F1A").Parameters[0], "R r1", RefKind.None, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: false); - VerifyParameterSymbol(baseType.GetMethod("F2A").Parameters[0], "scoped R r2", RefKind.None, DeclarationScope.ValueScoped, expectedHasUnscopedRefAttribute: false); - VerifyParameterSymbol(baseType.GetMethod("F3A").Parameters[0], "R r3", RefKind.None, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); - VerifyParameterSymbol(baseType.GetMethod("F4A").Parameters[0], "R r4", RefKind.None, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); + VerifyParameterSymbol(baseType.GetMethod("F1A").Parameters[0], "R r1", RefKind.None, ScopedKind.None, expectedHasUnscopedRefAttribute: false); + VerifyParameterSymbol(baseType.GetMethod("F2A").Parameters[0], "scoped R r2", RefKind.None, ScopedKind.ScopedValue, expectedHasUnscopedRefAttribute: false); + VerifyParameterSymbol(baseType.GetMethod("F3A").Parameters[0], "R r3", RefKind.None, ScopedKind.None, expectedHasUnscopedRefAttribute: true); + VerifyParameterSymbol(baseType.GetMethod("F4A").Parameters[0], "R r4", RefKind.None, ScopedKind.None, expectedHasUnscopedRefAttribute: true); } [Fact] @@ -22693,14 +23103,14 @@ static void F3([UnscopedRef] in R r3) { } }"; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics( - // (8,24): error CS9063: UnscopedRefAttribute cannot be applied to this item because it is unscoped by default. + // (8,24): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. // static void F1([UnscopedRef] R r1) { } // 1 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(8, 24)); - VerifyParameterSymbol(comp.GetMember("Program.F1").Parameters[0], "R r1", RefKind.None, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); - VerifyParameterSymbol(comp.GetMember("Program.F2").Parameters[0], "ref R r2", RefKind.Ref, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); - VerifyParameterSymbol(comp.GetMember("Program.F3").Parameters[0], "in R r3", RefKind.In, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); - VerifyParameterSymbol(comp.GetMember("Program.F4").Parameters[0], "out R r4", RefKind.Out, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); + VerifyParameterSymbol(comp.GetMember("Program.F1").Parameters[0], "R r1", RefKind.None, ScopedKind.None, expectedHasUnscopedRefAttribute: true); + VerifyParameterSymbol(comp.GetMember("Program.F2").Parameters[0], "ref R r2", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: true); + VerifyParameterSymbol(comp.GetMember("Program.F3").Parameters[0], "in R r3", RefKind.In, ScopedKind.None, expectedHasUnscopedRefAttribute: true); + VerifyParameterSymbol(comp.GetMember("Program.F4").Parameters[0], "out R r4", RefKind.Out, ScopedKind.None, expectedHasUnscopedRefAttribute: true); } [Fact] @@ -22946,10 +23356,10 @@ static void Main() var model = comp.GetSemanticModel(tree); var lambdas = tree.GetRoot().DescendantNodes().OfType().Select(e => model.GetSymbolInfo(e).Symbol.GetSymbol()).ToArray(); - VerifyParameterSymbol(lambdas[0].Parameters[0], "out System.Int32 i1", RefKind.Out, DeclarationScope.RefScoped, expectedHasUnscopedRefAttribute: false); - VerifyParameterSymbol(lambdas[1].Parameters[0], "out System.Int32 i2", RefKind.Out, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); - VerifyParameterSymbol(lambdas[2].Parameters[0], "out System.Object o1", RefKind.Out, DeclarationScope.RefScoped, expectedHasUnscopedRefAttribute: false); - VerifyParameterSymbol(lambdas[3].Parameters[0], "out System.Object o2", RefKind.Out, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); + VerifyParameterSymbol(lambdas[0].Parameters[0], "out System.Int32 i1", RefKind.Out, ScopedKind.ScopedRef, expectedHasUnscopedRefAttribute: false); + VerifyParameterSymbol(lambdas[1].Parameters[0], "out System.Int32 i2", RefKind.Out, ScopedKind.None, expectedHasUnscopedRefAttribute: true); + VerifyParameterSymbol(lambdas[2].Parameters[0], "out System.Object o1", RefKind.Out, ScopedKind.ScopedRef, expectedHasUnscopedRefAttribute: false); + VerifyParameterSymbol(lambdas[3].Parameters[0], "out System.Object o2", RefKind.Out, ScopedKind.None, expectedHasUnscopedRefAttribute: true); } [Fact] @@ -22982,10 +23392,10 @@ static void Main() var model = comp.GetSemanticModel(tree); var lambdas = tree.GetRoot().DescendantNodes().OfType().Select(e => model.GetSymbolInfo(e).Symbol.GetSymbol()).ToArray(); - VerifyParameterSymbol(lambdas[0].Parameters[0], "ref System.Int32 i1", RefKind.Ref, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: false); - VerifyParameterSymbol(lambdas[1].Parameters[0], "ref System.Int32 i2", RefKind.Ref, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); - VerifyParameterSymbol(lambdas[2].Parameters[0], "ref System.Object o1", RefKind.Ref, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: false); - VerifyParameterSymbol(lambdas[3].Parameters[0], "ref System.Object o2", RefKind.Ref, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); + VerifyParameterSymbol(lambdas[0].Parameters[0], "ref System.Int32 i1", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: false); + VerifyParameterSymbol(lambdas[1].Parameters[0], "ref System.Int32 i2", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: true); + VerifyParameterSymbol(lambdas[2].Parameters[0], "ref System.Object o1", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: false); + VerifyParameterSymbol(lambdas[3].Parameters[0], "ref System.Object o2", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: true); } [Fact] @@ -23019,10 +23429,10 @@ static void Main() var model = comp.GetSemanticModel(tree); var lambdas = tree.GetRoot().DescendantNodes().OfType().Select(e => model.GetSymbolInfo(e).Symbol.GetSymbol()).ToArray(); - VerifyParameterSymbol(lambdas[0].Parameters[0], "scoped ref R r1", RefKind.Ref, DeclarationScope.RefScoped, expectedHasUnscopedRefAttribute: false); - VerifyParameterSymbol(lambdas[1].Parameters[0], "ref R r2", RefKind.Ref, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: false); - VerifyParameterSymbol(lambdas[2].Parameters[0], "scoped ref R r1", RefKind.Ref, DeclarationScope.RefScoped, expectedHasUnscopedRefAttribute: false); - VerifyParameterSymbol(lambdas[3].Parameters[0], "ref R r2", RefKind.Ref, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: false); + VerifyParameterSymbol(lambdas[0].Parameters[0], "scoped ref R r1", RefKind.Ref, ScopedKind.ScopedRef, expectedHasUnscopedRefAttribute: false); + VerifyParameterSymbol(lambdas[1].Parameters[0], "ref R r2", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: false); + VerifyParameterSymbol(lambdas[2].Parameters[0], "scoped ref R r1", RefKind.Ref, ScopedKind.ScopedRef, expectedHasUnscopedRefAttribute: false); + VerifyParameterSymbol(lambdas[3].Parameters[0], "ref R r2", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: false); } [WorkItem(64569, "https://github.com/dotnet/roslyn/issues/64569")] @@ -23443,10 +23853,10 @@ static ref int F4() Diagnostic(ErrorCode.ERR_BindToBogus, "ScopedRefAndUnscopedRef").WithArguments("A.ScopedRefAndUnscopedRef(out int)").WithLocation(21, 22)); var typeA = comp.GetMember("A"); - VerifyParameterSymbol(typeA.GetMethod("NoAttributes").Parameters[0], "out System.Int32 i", RefKind.Out, DeclarationScope.RefScoped, expectedHasUnscopedRefAttribute: false); - VerifyParameterSymbol(typeA.GetMethod("ScopedRefOnly").Parameters[0], "out System.Int32 i", RefKind.Out, DeclarationScope.RefScoped, expectedHasUnscopedRefAttribute: false); - VerifyParameterSymbol(typeA.GetMethod("UnscopedRefOnly").Parameters[0], "out System.Int32 i", RefKind.Out, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); - VerifyParameterSymbol(typeA.GetMethod("ScopedRefAndUnscopedRef").Parameters[0], "out System.Int32 i", RefKind.Out, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); + VerifyParameterSymbol(typeA.GetMethod("NoAttributes").Parameters[0], "out System.Int32 i", RefKind.Out, ScopedKind.ScopedRef, expectedHasUnscopedRefAttribute: false); + VerifyParameterSymbol(typeA.GetMethod("ScopedRefOnly").Parameters[0], "out System.Int32 i", RefKind.Out, ScopedKind.ScopedRef, expectedHasUnscopedRefAttribute: false); + VerifyParameterSymbol(typeA.GetMethod("UnscopedRefOnly").Parameters[0], "out System.Int32 i", RefKind.Out, ScopedKind.None, expectedHasUnscopedRefAttribute: true); + VerifyParameterSymbol(typeA.GetMethod("ScopedRefAndUnscopedRef").Parameters[0], "out System.Int32 i", RefKind.Out, ScopedKind.None, expectedHasUnscopedRefAttribute: true); } [WorkItem(64778, "https://github.com/dotnet/roslyn/issues/64778")] @@ -23545,10 +23955,10 @@ static void F4(ref R x, ref R y) Diagnostic(ErrorCode.ERR_BindToBogus, "ScopedRefAndUnscopedRef").WithArguments("A.ScopedRefAndUnscopedRef(ref R, ref R)").WithLocation(17, 11)); var typeA = comp.GetMember("A"); - VerifyParameterSymbol(typeA.GetMethod("NoAttributes").Parameters[0], "ref R x", RefKind.Ref, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: false); - VerifyParameterSymbol(typeA.GetMethod("ScopedRefOnly").Parameters[0], "scoped ref R x", RefKind.Ref, DeclarationScope.RefScoped, expectedHasUnscopedRefAttribute: false); - VerifyParameterSymbol(typeA.GetMethod("UnscopedRefOnly").Parameters[0], "ref R x", RefKind.Ref, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); - VerifyParameterSymbol(typeA.GetMethod("ScopedRefAndUnscopedRef").Parameters[0], "ref R x", RefKind.Ref, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); + VerifyParameterSymbol(typeA.GetMethod("NoAttributes").Parameters[0], "ref R x", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: false); + VerifyParameterSymbol(typeA.GetMethod("ScopedRefOnly").Parameters[0], "scoped ref R x", RefKind.Ref, ScopedKind.ScopedRef, expectedHasUnscopedRefAttribute: false); + VerifyParameterSymbol(typeA.GetMethod("UnscopedRefOnly").Parameters[0], "ref R x", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: true); + VerifyParameterSymbol(typeA.GetMethod("ScopedRefAndUnscopedRef").Parameters[0], "ref R x", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: true); } // As above, but with ref readonly parameters. @@ -23653,10 +24063,10 @@ static void F4(in R x, ref R y) Diagnostic(ErrorCode.ERR_BindToBogus, "ScopedRefAndUnscopedRef").WithArguments("A.ScopedRefAndUnscopedRef(in R, ref R)").WithLocation(17, 11)); var typeA = comp.GetMember("A"); - VerifyParameterSymbol(typeA.GetMethod("NoAttributes").Parameters[0], "in R x", RefKind.In, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: false); - VerifyParameterSymbol(typeA.GetMethod("ScopedRefOnly").Parameters[0], "scoped in R x", RefKind.In, DeclarationScope.RefScoped, expectedHasUnscopedRefAttribute: false); - VerifyParameterSymbol(typeA.GetMethod("UnscopedRefOnly").Parameters[0], "in R x", RefKind.In, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); - VerifyParameterSymbol(typeA.GetMethod("ScopedRefAndUnscopedRef").Parameters[0], "in R x", RefKind.In, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); + VerifyParameterSymbol(typeA.GetMethod("NoAttributes").Parameters[0], "in R x", RefKind.In, ScopedKind.None, expectedHasUnscopedRefAttribute: false); + VerifyParameterSymbol(typeA.GetMethod("ScopedRefOnly").Parameters[0], "scoped in R x", RefKind.In, ScopedKind.ScopedRef, expectedHasUnscopedRefAttribute: false); + VerifyParameterSymbol(typeA.GetMethod("UnscopedRefOnly").Parameters[0], "in R x", RefKind.In, ScopedKind.None, expectedHasUnscopedRefAttribute: true); + VerifyParameterSymbol(typeA.GetMethod("ScopedRefAndUnscopedRef").Parameters[0], "in R x", RefKind.In, ScopedKind.None, expectedHasUnscopedRefAttribute: true); } [Fact] @@ -23711,11 +24121,11 @@ static void F5(in R r5) { } bool useUpdatedRules = languageVersion == LanguageVersion.CSharp11; - VerifyParameterSymbol(comp.GetMember("S1.F1").ThisParameter, "ref S1 this", RefKind.Ref, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("S2.F2").ThisParameter, "in S2 this", RefKind.In, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("A.F3").Parameters[0], "out System.Int32 i3", RefKind.Out, useUpdatedRules ? DeclarationScope.RefScoped : DeclarationScope.Unscoped); - VerifyParameterSymbol(comp.GetMember("A.F4").Parameters[0], "ref R r4", RefKind.Ref, DeclarationScope.Unscoped); - VerifyParameterSymbol(comp.GetMember("A.F5").Parameters[0], "in R r5", RefKind.In, DeclarationScope.Unscoped); + VerifyParameterSymbol(comp.GetMember("S1.F1").ThisParameter, "ref S1 this", RefKind.Ref, ScopedKind.ScopedRef); + VerifyParameterSymbol(comp.GetMember("S2.F2").ThisParameter, "in S2 this", RefKind.In, ScopedKind.ScopedRef); + VerifyParameterSymbol(comp.GetMember("A.F3").Parameters[0], "out System.Int32 i3", RefKind.Out, useUpdatedRules ? ScopedKind.ScopedRef : ScopedKind.None); + VerifyParameterSymbol(comp.GetMember("A.F4").Parameters[0], "ref R r4", RefKind.Ref, ScopedKind.None); + VerifyParameterSymbol(comp.GetMember("A.F5").Parameters[0], "in R r5", RefKind.In, ScopedKind.None); } [Theory] @@ -23754,11 +24164,11 @@ public static void F5(in R r5) { } bool useUpdatedRules = languageVersionA == LanguageVersion.CSharp11; - VerifyParameterSymbol(comp.GetMember("S1.F1").ThisParameter, "ref S1 this", RefKind.Ref, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("S2.F2").ThisParameter, "in S2 this", RefKind.In, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("A.F3").Parameters[0], "out System.Int32 i3", RefKind.Out, useUpdatedRules ? DeclarationScope.RefScoped : DeclarationScope.Unscoped); - VerifyParameterSymbol(comp.GetMember("A.F4").Parameters[0], "ref R r4", RefKind.Ref, DeclarationScope.Unscoped); - VerifyParameterSymbol(comp.GetMember("A.F5").Parameters[0], "in R r5", RefKind.In, DeclarationScope.Unscoped); + VerifyParameterSymbol(comp.GetMember("S1.F1").ThisParameter, "ref S1 this", RefKind.Ref, ScopedKind.ScopedRef); + VerifyParameterSymbol(comp.GetMember("S2.F2").ThisParameter, "in S2 this", RefKind.In, ScopedKind.ScopedRef); + VerifyParameterSymbol(comp.GetMember("A.F3").Parameters[0], "out System.Int32 i3", RefKind.Out, useUpdatedRules ? ScopedKind.ScopedRef : ScopedKind.None); + VerifyParameterSymbol(comp.GetMember("A.F4").Parameters[0], "ref R r4", RefKind.Ref, ScopedKind.None); + VerifyParameterSymbol(comp.GetMember("A.F5").Parameters[0], "in R r5", RefKind.In, ScopedKind.None); } [Theory] @@ -23788,13 +24198,13 @@ static void Main() bool useUpdatedRules = languageVersion == LanguageVersion.CSharp11; - verifyParameter(delegateTypesAndLambdas[0], 0, "out System.Int32", "i1", RefKind.Out, useUpdatedRules ? DeclarationScope.RefScoped : DeclarationScope.Unscoped); - verifyParameter(delegateTypesAndLambdas[1], 0, "R", "r2", RefKind.None, DeclarationScope.Unscoped); - verifyParameter(delegateTypesAndLambdas[2], 0, "ref R", "r3", RefKind.Ref, DeclarationScope.Unscoped); - verifyParameter(delegateTypesAndLambdas[3], 0, "in R", "r4", RefKind.In, DeclarationScope.Unscoped); - verifyParameter(delegateTypesAndLambdas[4], 0, "out R", "r5", RefKind.Out, useUpdatedRules ? DeclarationScope.RefScoped : DeclarationScope.Unscoped); + verifyParameter(delegateTypesAndLambdas[0], 0, "out System.Int32", "i1", RefKind.Out, useUpdatedRules ? ScopedKind.ScopedRef : ScopedKind.None); + verifyParameter(delegateTypesAndLambdas[1], 0, "R", "r2", RefKind.None, ScopedKind.None); + verifyParameter(delegateTypesAndLambdas[2], 0, "ref R", "r3", RefKind.Ref, ScopedKind.None); + verifyParameter(delegateTypesAndLambdas[3], 0, "in R", "r4", RefKind.In, ScopedKind.None); + verifyParameter(delegateTypesAndLambdas[4], 0, "out R", "r5", RefKind.Out, useUpdatedRules ? ScopedKind.ScopedRef : ScopedKind.None); - static void verifyParameter((NamedTypeSymbol, LambdaSymbol) delegateTypeAndLambda, int parameterIndex, string expectedDisplayType, string expectedDisplayName, RefKind expectedRefKind, DeclarationScope expectedScope) + static void verifyParameter((NamedTypeSymbol, LambdaSymbol) delegateTypeAndLambda, int parameterIndex, string expectedDisplayType, string expectedDisplayName, RefKind expectedRefKind, ScopedKind expectedScope) { var (delegateType, lambda) = delegateTypeAndLambda; VerifyParameterSymbol(delegateType.DelegateInvokeMethod.Parameters[parameterIndex], $"{expectedDisplayType} arg", expectedRefKind, expectedScope); @@ -23838,11 +24248,11 @@ unsafe public class A bool useUpdatedRules = languageVersionA == LanguageVersion.CSharp11; - VerifyParameterSymbol(getFunctionPointerMethod(comp, "A.F1").Parameters[0], "out modreq(System.Runtime.InteropServices.OutAttribute) System.Int32", RefKind.Out, useUpdatedRules ? DeclarationScope.RefScoped : DeclarationScope.Unscoped); - VerifyParameterSymbol(getFunctionPointerMethod(comp, "A.F2").Parameters[0], "R", RefKind.None, DeclarationScope.Unscoped); - VerifyParameterSymbol(getFunctionPointerMethod(comp, "A.F3").Parameters[0], "ref R", RefKind.Ref, DeclarationScope.Unscoped); - VerifyParameterSymbol(getFunctionPointerMethod(comp, "A.F4").Parameters[0], "in modreq(System.Runtime.InteropServices.InAttribute) R", RefKind.In, DeclarationScope.Unscoped); - VerifyParameterSymbol(getFunctionPointerMethod(comp, "A.F5").Parameters[0], "out modreq(System.Runtime.InteropServices.OutAttribute) R", RefKind.Out, useUpdatedRules ? DeclarationScope.RefScoped : DeclarationScope.Unscoped); + VerifyParameterSymbol(getFunctionPointerMethod(comp, "A.F1").Parameters[0], "out modreq(System.Runtime.InteropServices.OutAttribute) System.Int32", RefKind.Out, useUpdatedRules ? ScopedKind.ScopedRef : ScopedKind.None); + VerifyParameterSymbol(getFunctionPointerMethod(comp, "A.F2").Parameters[0], "R", RefKind.None, ScopedKind.None); + VerifyParameterSymbol(getFunctionPointerMethod(comp, "A.F3").Parameters[0], "ref R", RefKind.Ref, ScopedKind.None); + VerifyParameterSymbol(getFunctionPointerMethod(comp, "A.F4").Parameters[0], "in modreq(System.Runtime.InteropServices.InAttribute) R", RefKind.In, ScopedKind.None); + VerifyParameterSymbol(getFunctionPointerMethod(comp, "A.F5").Parameters[0], "out modreq(System.Runtime.InteropServices.OutAttribute) R", RefKind.Out, useUpdatedRules ? ScopedKind.ScopedRef : ScopedKind.None); static MethodSymbol getFunctionPointerMethod(CSharpCompilation comp, string qualifiedName) => ((FunctionPointerTypeSymbol)comp.GetMember(qualifiedName).Type).Signature; @@ -23874,37 +24284,37 @@ static void F5([UnscopedRef] out R r5) { } if (languageVersion == LanguageVersion.CSharp11) { comp.VerifyEmitDiagnostics( - // (11,21): error CS9063: UnscopedRefAttribute cannot be applied to this item because it is unscoped by default. + // (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)); } else { comp.VerifyEmitDiagnostics( - // (10,21): error CS9063: UnscopedRefAttribute cannot be applied to this item because it is unscoped by default. + // (10,21): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. // static void F1([UnscopedRef] out int i1) { i1 = 0; } Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(10, 21), - // (11,21): error CS9063: UnscopedRefAttribute cannot be applied to this item because it is unscoped by default. + // (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 item because it is unscoped by default. + // (12,21): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. // 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 item because it is unscoped by default. + // (13,21): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. // 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 item because it is unscoped by default. + // (14,21): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. // static void F5([UnscopedRef] out R r5) { } Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(14, 21)); } - VerifyParameterSymbol(comp.GetMember("S.F").ThisParameter, "ref S this", RefKind.Ref, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); - VerifyParameterSymbol(comp.GetMember("S.P").GetMethod.ThisParameter, "ref S this", RefKind.Ref, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); - VerifyParameterSymbol(comp.GetMember("Program.F1").Parameters[0], "out System.Int32 i1", RefKind.Out, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); - VerifyParameterSymbol(comp.GetMember("Program.F2").Parameters[0], "R r2", RefKind.None, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); - VerifyParameterSymbol(comp.GetMember("Program.F3").Parameters[0], "ref R r3", RefKind.Ref, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); - VerifyParameterSymbol(comp.GetMember("Program.F4").Parameters[0], "in R r4", RefKind.In, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); - VerifyParameterSymbol(comp.GetMember("Program.F5").Parameters[0], "out R r5", RefKind.Out, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); + 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); + 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); + VerifyParameterSymbol(comp.GetMember("Program.F4").Parameters[0], "in R r4", RefKind.In, ScopedKind.None, expectedHasUnscopedRefAttribute: true); + VerifyParameterSymbol(comp.GetMember("Program.F5").Parameters[0], "out R r5", RefKind.Out, ScopedKind.None, expectedHasUnscopedRefAttribute: true); } [Theory] @@ -24517,17 +24927,700 @@ static void F4(in R x, ref R y) static void verifyParameters(NamedTypeSymbol typeA) { - VerifyParameterSymbol(typeA.GetMethod("F1").Parameters[0], "ref R x", RefKind.Ref, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: false); - VerifyParameterSymbol(typeA.GetMethod("F2").Parameters[0], "ref R x", RefKind.Ref, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); - VerifyParameterSymbol(typeA.GetMethod("F3").Parameters[0], "in R x", RefKind.In, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: false); - VerifyParameterSymbol(typeA.GetMethod("F4").Parameters[0], "in R x", RefKind.In, DeclarationScope.Unscoped, expectedHasUnscopedRefAttribute: true); + VerifyParameterSymbol(typeA.GetMethod("F1").Parameters[0], "ref R x", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: false); + VerifyParameterSymbol(typeA.GetMethod("F2").Parameters[0], "ref R x", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: true); + VerifyParameterSymbol(typeA.GetMethod("F3").Parameters[0], "in R x", RefKind.In, ScopedKind.None, expectedHasUnscopedRefAttribute: false); + VerifyParameterSymbol(typeA.GetMethod("F4").Parameters[0], "in R x", RefKind.In, ScopedKind.None, expectedHasUnscopedRefAttribute: true); } } - [Theory] - [InlineData(0)] - [InlineData(-1)] - [InlineData(11)] + [Fact] + [WorkItem(64508, "https://github.com/dotnet/roslyn/issues/64508")] + public void UnscopedRefAttribute_InterfaceImplementation_01() + { + string source = """ + using System.Diagnostics.CodeAnalysis; + ref struct R + { + public R(ref T t) { } + } + interface I + { + ref T F1(); + void F2(); + void F3(out R r); + ref T P { get; } + } + struct S1 : I + { + public ref int F1() => throw null; + public void F2() { } + public void F3(out R r) { r = default; } + public ref int P => throw null; + } + struct S2 : I + { + private int _f2; + [UnscopedRef] public ref int F1() => ref _f2; // 1 + [UnscopedRef] public void F2() { } // 2 + [UnscopedRef] public void F3(out R r) { r = new R(ref _f2); } // 3 + [UnscopedRef] public ref int P => ref _f2; // 4 + } + struct S3 : I + { + ref int I.F1() => throw null; + void I.F2() { } + void I.F3(out R r) { r = default; } + ref int I.P => throw null; + } + struct S4 : I + { + private int _f4; + [UnscopedRef] ref int I.F1() => ref _f4; // 5 + [UnscopedRef] void I.F2() { } // 6 + [UnscopedRef] void I.F3(out R r) { r = new R(ref _f4); } // 7 + [UnscopedRef] ref int I.P => ref _f4; // 8 + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics( + // (23,34): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + // [UnscopedRef] public ref int F1() => ref _f2; // 1 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F1").WithLocation(23, 34), + // (24,31): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + // [UnscopedRef] public void F2() { } // 2 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F2").WithLocation(24, 31), + // (25,31): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + // [UnscopedRef] public void F3(out R r) { r = new R(ref _f2); } // 3 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F3").WithLocation(25, 31), + // (26,39): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + // [UnscopedRef] public ref int P => ref _f2; // 4 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "ref _f2").WithLocation(26, 39), + // (38,34): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + // [UnscopedRef] ref int I.F1() => ref _f4; // 5 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F1").WithLocation(38, 34), + // (39,31): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + // [UnscopedRef] void I.F2() { } // 6 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F2").WithLocation(39, 31), + // (40,31): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + // [UnscopedRef] void I.F3(out R r) { r = new R(ref _f4); } // 7 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F3").WithLocation(40, 31), + // (41,39): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + // [UnscopedRef] ref int I.P => ref _f4; // 8 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "ref _f4").WithLocation(41, 39)); + } + + // As above, but interface members are also marked [UnscopedRef]. + [Fact] + [WorkItem(64508, "https://github.com/dotnet/roslyn/issues/64508")] + public void UnscopedRefAttribute_InterfaceImplementation_02() + { + string source = """ + using System.Diagnostics.CodeAnalysis; + ref struct R + { + public R(ref T t) { } + } + interface I + { + [UnscopedRef] ref T F1(); // 1 + [UnscopedRef] void F2(); // 2 + [UnscopedRef] void F3(out R r); // 3 + [UnscopedRef] ref T P { get; } // 4 + } + struct S1 : I + { + public ref int F1() => throw null; + public void F2() { } + public void F3(out R r) { r = default; } + public ref int P => throw null; + } + struct S2 : I + { + private int _f2; + [UnscopedRef] public ref int F1() => ref _f2; // 5 + [UnscopedRef] public void F2() { } // 6 + [UnscopedRef] public void F3(out R r) { r = new R(ref _f2); } // 7 + [UnscopedRef] public ref int P => ref _f2; // 8 + } + struct S3 : I + { + ref int I.F1() => throw null; + void I.F2() { } + void I.F3(out R r) { r = default; } + ref int I.P => throw null; + } + struct S4 : I + { + private int _f4; + [UnscopedRef] ref int I.F1() => ref _f4; // 9 + [UnscopedRef] void I.F2() { } // 10 + [UnscopedRef] void I.F3(out R r) { r = new R(ref _f4); } // 11 + [UnscopedRef] ref int I.P => ref _f4; // 12 + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics( + // (8,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] ref T F1(); // 1 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(8, 6), + // (9,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] void F2(); // 2 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(9, 6), + // (10,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] void F3(out R r); // 3 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(10, 6), + // (11,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] ref T P { get; } // 4 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(11, 6), + // (23,34): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + // [UnscopedRef] public ref int F1() => ref _f2; // 5 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F1").WithLocation(23, 34), + // (24,31): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + // [UnscopedRef] public void F2() { } // 6 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F2").WithLocation(24, 31), + // (25,31): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + // [UnscopedRef] public void F3(out R r) { r = new R(ref _f2); } // 7 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F3").WithLocation(25, 31), + // (26,39): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + // [UnscopedRef] public ref int P => ref _f2; // 8 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "ref _f2").WithLocation(26, 39), + // (38,34): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + // [UnscopedRef] ref int I.F1() => ref _f4; // 9 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F1").WithLocation(38, 34), + // (39,31): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + // [UnscopedRef] void I.F2() { } // 10 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F2").WithLocation(39, 31), + // (40,31): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + // [UnscopedRef] void I.F3(out R r) { r = new R(ref _f4); } // 11 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F3").WithLocation(40, 31), + // (41,39): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + // [UnscopedRef] ref int I.P => ref _f4; // 12 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "ref _f4").WithLocation(41, 39)); + } + + [Fact] + [WorkItem(64508, "https://github.com/dotnet/roslyn/issues/64508")] + public void UnscopedRefAttribute_InterfaceImplementation_03() + { + string source = """ + using System.Diagnostics.CodeAnalysis; + interface I1 + { + ref T P1 { get; } + } + interface I2 + { + T P2 { get; set; } + } + interface I3 + { + T P3 { set; } + } + struct S1 : I1, I2 + { + [UnscopedRef] public ref int P1 => throw null; // 1 + [UnscopedRef] public int P2 { get; set; } // 2, 3 + } + struct S2 : I1, I2 + { + public ref int P1 { [UnscopedRef] get => throw null; } // 4 + public int P2 { [UnscopedRef] get; set; } // 5 + } + struct S3 : I2, I3 + { + public int P2 { get; [UnscopedRef] set; } // 6 + public int P3 { [UnscopedRef] set { } } // 7 + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics( + // (16,40): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + // [UnscopedRef] public ref int P1 => throw null; // 1 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "throw null").WithLocation(16, 40), + // (17,35): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + // [UnscopedRef] public int P2 { get; set; } // 2, 3 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "get").WithLocation(17, 35), + // (17,40): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + // [UnscopedRef] public int P2 { get; set; } // 2, 3 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "set").WithLocation(17, 40), + // (21,39): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + // public ref int P1 { [UnscopedRef] get => throw null; } // 4 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "get").WithLocation(21, 39), + // (22,35): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + // public int P2 { [UnscopedRef] get; set; } // 5 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "get").WithLocation(22, 35), + // (26,40): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + // public int P2 { get; [UnscopedRef] set; } // 6 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "set").WithLocation(26, 40), + // (27,35): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + // public int P3 { [UnscopedRef] set { } } // 7 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "set").WithLocation(27, 35)); + } + + [Fact] + public void UnscopedRefAttribute_InterfaceImplementation_04() + { + string source = """ + using System.Diagnostics.CodeAnalysis; + interface I + { + ref T F(); + ref T P { get; } + } + struct S : I + { + private int _f; + [UnscopedRef] public ref int F() => ref _f; + [UnscopedRef] public ref int P => ref _f; + ref int I.F() => throw null; + ref int I.P => throw null; + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void UnscopedRefAttribute_InterfaceImplementation_05() + { + string source = """ + using System.Diagnostics.CodeAnalysis; + interface I + { + ref T F1(); + [UnscopedRef] ref T F2(); // 1 + } + class C1 : I + { + private int _f1; + [UnscopedRef] public ref int F1() => ref _f1; // 2 + [UnscopedRef] public ref int F2() => ref _f1; // 3 + } + class C2 : I + { + private int _f2; + [UnscopedRef] ref int I.F1() => ref _f2; // 4 + [UnscopedRef] ref int I.F2() => ref _f2; // 5 + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics( + // (5,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] ref T F2(); // 1 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(5, 6), + // (10,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] public ref int F1() => ref _f1; // 2 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(10, 6), + // (11,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] public ref int F2() => ref _f1; // 3 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(11, 6), + // (16,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] ref int I.F1() => ref _f2; // 4 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(16, 6), + // (17,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] ref int I.F2() => ref _f2; // 5 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(17, 6)); + } + + [Fact] + public void UnscopedRefAttribute_InterfaceImplementation_06() + { + string source = """ + using System.Diagnostics.CodeAnalysis; + interface I + { + ref T F(); + ref T P { get; } + } + class A + { + [UnscopedRef] public ref int F() => throw null; // 1 + [UnscopedRef] public ref int P => throw null; // 2 + } + class B : A, I + { + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics( + // (9,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] public ref int F() => throw null; // 1 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(9, 6), + // (10,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] public ref int P => throw null; // 2 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(10, 6)); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public void UnscopedRefAttribute_InterfaceImplementation_07() + { + string source = """ + using System.Diagnostics.CodeAnalysis; + interface IA + { + ref T F(); + ref T P { get; } + } + interface IB : IA + { + [UnscopedRef] ref int IA.F() => throw null; // 1 + [UnscopedRef] ref int IA.P => throw null; // 2 + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics( + // (9,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] ref int IA.F() => throw null; // 1 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(9, 6), + // (10,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] ref int IA.P => throw null; // 2 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(10, 6)); + } + + [Fact] + public void UnscopedRefAttribute_InterfaceImplementation_08() + { + string source = """ + #pragma warning disable 67 + using System.Diagnostics.CodeAnalysis; + delegate void D(); + interface I + { + event D E; + } + class C1 : I + { + [UnscopedRef] public event D E; // 1 + } + class C2 : I + { + [UnscopedRef] public event D E { add { } remove { } } // 2 + } + class C3 : I + { + [UnscopedRef] event D I.E { add { } remove { } } // 3 + } + struct S1 : I + { + [UnscopedRef] public event D E; // 4 + } + struct S2 : I + { + [UnscopedRef] public event D E { add { } remove { } } // 5 + } + struct S3 : I + { + [UnscopedRef] event D I.E { add { } remove { } } // 6 + } + """; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyEmitDiagnostics( + // (10,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] public event D E; // 1 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(10, 6), + // (14,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] public event D E { add { } remove { } } // 2 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(14, 6), + // (18,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] event D I.E { add { } remove { } } // 3 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(18, 6), + // (22,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] public event D E; // 4 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(22, 6), + // (26,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] public event D E { add { } remove { } } // 5 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(26, 6), + // (30,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] event D I.E { add { } remove { } } // 6 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(30, 6)); + } + + [Fact] + public void UnscopedRefAttribute_InterfaceImplementation_09() + { + string source = """ + #pragma warning disable 67 + using System.Diagnostics.CodeAnalysis; + delegate void D(); + interface I + { + event D E1; + event D E2; + } + class C1 : I + { + public event D E1 { [UnscopedRef] add { } remove { } } // 1 + public event D E2 { add { } [UnscopedRef] remove { } } // 2 + } + class C2 : I + { + event D I.E1 { [UnscopedRef] add { } remove { } } // 3 + event D I.E2 { add { } [UnscopedRef] remove { } } // 4 + } + struct S1 : I + { + public event D E1 { [UnscopedRef] add { } remove { } } // 5 + public event D E2 { add { } [UnscopedRef] remove { } } // 6 + } + struct S2 : I + { + event D I.E1 { [UnscopedRef] add { } remove { } } // 7 + event D I.E2 { add { } [UnscopedRef] remove { } } // 8 + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics( + // (11,31): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // public event D E1 { [UnscopedRef] add { } remove { } } // 1 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(11, 31), + // (12,39): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // public event D E2 { add { } [UnscopedRef] remove { } } // 2 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(12, 39), + // (16,37): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // event D I.E1 { [UnscopedRef] add { } remove { } } // 3 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(16, 37), + // (17,45): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // event D I.E2 { add { } [UnscopedRef] remove { } } // 4 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(17, 45), + // (21,31): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // public event D E1 { [UnscopedRef] add { } remove { } } // 5 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(21, 31), + // (22,39): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // public event D E2 { add { } [UnscopedRef] remove { } } // 6 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(22, 39), + // (26,37): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // event D I.E1 { [UnscopedRef] add { } remove { } } // 7 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(26, 37), + // (27,45): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // event D I.E2 { add { } [UnscopedRef] remove { } } // 8 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(27, 45)); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public void UnscopedRefAttribute_InterfaceImplementation_10() + { + string source = """ + using System.Diagnostics.CodeAnalysis; + delegate void D(); + interface I + { + event D E; + } + interface IA : I + { + [UnscopedRef] event D I.E { add { } remove { } } // 1 + } + interface IB : I + { + event D I.E { [UnscopedRef] add { } remove { } } // 2 + } + interface IC : I + { + event D I.E { add { } [UnscopedRef] remove { } } // 3 + } + """; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, targetFramework: TargetFramework.Net60); + comp.VerifyEmitDiagnostics( + // (9,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] event D I.E { add { } remove { } } // 1 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(9, 6), + // (13,36): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // event D I.E { [UnscopedRef] add { } remove { } } // 2 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(13, 36), + // (17,44): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // event D I.E { add { } [UnscopedRef] remove { } } // 3 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(17, 44)); + } + + [Fact] + public void UnscopedRefAttribute_InterfaceImplementation_11() + { + string source = """ + #pragma warning disable 67 + using System.Diagnostics.CodeAnalysis; + delegate void D(); + interface I + { + [UnscopedRef] event D E; // 1 + } + class C : I + { + [UnscopedRef] public event D E; // 2 + } + struct S : I + { + [UnscopedRef] event D I.E { add { } remove { } } // 3 + } + """; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyEmitDiagnostics( + // (6,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] event D E; // 1 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(6, 6), + // (10,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] public event D E; // 2 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(10, 6), + // (14,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] event D I.E { add { } remove { } } // 3 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(14, 6)); + } + + [Theory] + [InlineData("class")] + [InlineData("struct")] + public void UnscopedRefAttribute_InterfaceImplementation_12(string type) + { + string source = $$""" + using System.Diagnostics.CodeAnalysis; + delegate void D(); + ref struct R { } + interface I + { + static abstract R F(); + static abstract R P1 { get; } + static abstract R P2 { get; set; } + static abstract event D E; + } + {{type}} C1 : I + { + [UnscopedRef] public static R F() => default; // 1 + [UnscopedRef] public static R P1 { get { return default; } set { } } // 2 + public static R P2 { [UnscopedRef] get { return default; } [UnscopedRef] set { } } // 3, 4 + public static event D E { [UnscopedRef] add { } [UnscopedRef] remove { } } // 5, 6 + } + {{type}} C2 : I + { + [UnscopedRef] static R I.F() => default; // 7 + [UnscopedRef] static R I.P1 => default; // 8 + static R I.P2 { [UnscopedRef] get { return default; } [UnscopedRef] set { } } // 9, 10 + static event D I.E { [UnscopedRef] add { } [UnscopedRef] remove { } } // 11, 12 + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics( + // (13,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] public static R F() => default; // 1 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(13, 6), + // (14,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] public static R P1 { get { return default; } set { } } // 2 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(14, 6), + // (15,32): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // public static R P2 { [UnscopedRef] get { return default; } [UnscopedRef] set { } } // 3, 4 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(15, 32), + // (15,70): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // public static R P2 { [UnscopedRef] get { return default; } [UnscopedRef] set { } } // 3, 4 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(15, 70), + // (16,37): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // public static event D E { [UnscopedRef] add { } [UnscopedRef] remove { } } // 5, 6 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(16, 37), + // (16,59): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // public static event D E { [UnscopedRef] add { } [UnscopedRef] remove { } } // 5, 6 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(16, 59), + // (20,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] static R I.F() => default; // 7 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(20, 6), + // (21,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] static R I.P1 => default; // 8 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(21, 6), + // (22,38): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // static R I.P2 { [UnscopedRef] get { return default; } [UnscopedRef] set { } } // 9, 10 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(22, 38), + // (22,76): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // static R I.P2 { [UnscopedRef] get { return default; } [UnscopedRef] set { } } // 9, 10 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(22, 76), + // (23,43): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // static event D I.E { [UnscopedRef] add { } [UnscopedRef] remove { } } // 11, 12 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(23, 43), + // (23,65): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // static event D I.E { [UnscopedRef] add { } [UnscopedRef] remove { } } // 11, 12 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(23, 65)); + } + + [Fact] + public void UnscopedRefAttribute_InterfaceImplementation_13() + { + string source = """ + using System.Diagnostics.CodeAnalysis; + delegate void D(); + ref struct R { } + interface IA + { + static abstract R F(); + static abstract R P1 { get; } + static abstract R P2 { get; set; } + static abstract event D E; + } + interface IB : IA + { + [UnscopedRef] static R IA.F() => default; // 1 + [UnscopedRef] static R IA.P1 => default; // 2 + static R IA.P2 { [UnscopedRef] get { return default; } [UnscopedRef] set { } } // 3, 4 + static event D IA.E { [UnscopedRef] add { } [UnscopedRef] remove { } } // 5, 6 + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics( + // (13,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] static R IA.F() => default; // 1 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(13, 6), + // (14,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] static R IA.P1 => default; // 2 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(14, 6), + // (15,39): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // static R IA.P2 { [UnscopedRef] get { return default; } [UnscopedRef] set { } } // 3, 4 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(15, 39), + // (15,77): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // static R IA.P2 { [UnscopedRef] get { return default; } [UnscopedRef] set { } } // 3, 4 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(15, 77), + // (16,44): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // static event D IA.E { [UnscopedRef] add { } [UnscopedRef] remove { } } // 5, 6 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(16, 44), + // (16,66): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // static event D IA.E { [UnscopedRef] add { } [UnscopedRef] remove { } } // 5, 6 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(16, 66)); + } + + [Fact] + public void UnscopedRefAttribute_Overrides_07() + { + string source = """ + using System.Diagnostics.CodeAnalysis; + abstract class A + { + public abstract ref T F1(); + [UnscopedRef] public abstract ref T F2(); // 1 + } + class B1 : A + { + private int _f1; + public override ref int F1() => ref _f1; + public override ref int F2() => ref _f1; + } + class B2 : A + { + private string _f2; + [UnscopedRef] public override ref string F1() => ref _f2; // 2 + [UnscopedRef] public override ref string F2() => ref _f2; // 3 + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics( + // (5,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] public abstract ref T F2(); // 1 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(5, 6), + // (16,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] public override ref string F1() => ref _f2; // 2 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(16, 6), + // (17,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] public override ref string F2() => ref _f2; // 3 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(17, 6)); + } + + [Theory] + [InlineData(0)] + [InlineData(-1)] + [InlineData(11)] [InlineData(int.MinValue)] [InlineData(int.MaxValue)] public void RefSafetyRulesAttribute_Version(int version) @@ -24562,7 +25655,7 @@ .class public A comp.VerifyDiagnostics(); var method = comp.GetMember("A.F1"); - VerifyParameterSymbol(method.Parameters[0], "out System.Int32 i", RefKind.Out, DeclarationScope.RefScoped); + VerifyParameterSymbol(method.Parameters[0], "out System.Int32 i", RefKind.Out, ScopedKind.ScopedRef); Assert.True(method.ContainingModule.UseUpdatedEscapeRules); } @@ -24612,7 +25705,7 @@ public void UseUpdatedEscapeRules(LanguageVersion languageVersion, TargetFramewo } var method = comp.GetMember("Program.F1"); - VerifyParameterSymbol(method.Parameters[0], "out T t", RefKind.Out, expectedUseUpdatedEscapeRules ? DeclarationScope.RefScoped : DeclarationScope.Unscoped); + VerifyParameterSymbol(method.Parameters[0], "out T t", RefKind.Out, expectedUseUpdatedEscapeRules ? ScopedKind.ScopedRef : ScopedKind.None); Assert.Equal(expectedUseUpdatedEscapeRules, method.UseUpdatedEscapeRules); Assert.Equal(expectedUseUpdatedEscapeRules, method.ContainingModule.UseUpdatedEscapeRules); @@ -24848,7 +25941,7 @@ public void M() var type = (NamedTypeSymbol)model.GetDeclaredSymbol(node).GetSymbol().Type; Assert.True(type.IsImplicitlyDeclared); Assert.True(type.IsAnonymousType); - Assert.Equal(DeclarationScope.Unscoped, type.DelegateInvokeMethod.Parameters.Single().EffectiveScope); + Assert.Equal(ScopedKind.None, type.DelegateInvokeMethod.Parameters.Single().EffectiveScope); } Assert.Equal(3, count); @@ -24900,7 +25993,7 @@ public void M() var type = (NamedTypeSymbol)model.GetDeclaredSymbol(node).GetSymbol().Type; Assert.True(type.IsImplicitlyDeclared); Assert.True(type.IsAnonymousType); - Assert.Equal(DeclarationScope.Unscoped, type.DelegateInvokeMethod.Parameters.Single().EffectiveScope); + Assert.Equal(ScopedKind.None, type.DelegateInvokeMethod.Parameters.Single().EffectiveScope); } Assert.Equal(3, count); @@ -24952,7 +26045,7 @@ void C([UnscopedRef] out RefStruct s) { } var type = (NamedTypeSymbol)model.GetDeclaredSymbol(node).GetSymbol().Type; Assert.True(type.IsImplicitlyDeclared); Assert.True(type.IsAnonymousType); - Assert.Equal(DeclarationScope.Unscoped, type.DelegateInvokeMethod.Parameters.Single().EffectiveScope); + Assert.Equal(ScopedKind.None, type.DelegateInvokeMethod.Parameters.Single().EffectiveScope); } Assert.Equal(3, count); @@ -25104,9 +26197,9 @@ static void verify(CSharpCompilation comp) var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol()).ToArray(); - VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[1], "scoped ref R r2", RefKind.Ref, DeclarationScope.RefScoped); - VerifyLocalSymbol(locals[2], "scoped ref readonly R r5", RefKind.RefReadOnly, DeclarationScope.RefScoped); + VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[1], "scoped ref R r2", RefKind.Ref, ScopedKind.ScopedRef); + VerifyLocalSymbol(locals[2], "scoped ref readonly R r5", RefKind.RefReadOnly, ScopedKind.ScopedRef); foreach (var decl in decls) { @@ -25194,9 +26287,9 @@ static void verify(CSharpCompilation comp) var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol()).ToArray(); - VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[1], "scoped ref R r2", RefKind.Ref, DeclarationScope.RefScoped); - VerifyLocalSymbol(locals[2], "scoped ref readonly R r5", RefKind.RefReadOnly, DeclarationScope.RefScoped); + VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[1], "scoped ref R r2", RefKind.Ref, ScopedKind.ScopedRef); + VerifyLocalSymbol(locals[2], "scoped ref readonly R r5", RefKind.RefReadOnly, ScopedKind.ScopedRef); foreach (var decl in decls) { @@ -25314,12 +26407,12 @@ static void verify(CSharpCompilation comp) var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol()).ToArray(); - VerifyLocalSymbol(locals[0], "scoped s1", RefKind.None, DeclarationScope.Unscoped); - VerifyLocalSymbol(locals[1], "ref scoped s2", RefKind.Ref, DeclarationScope.Unscoped); - VerifyLocalSymbol(locals[2], "ref scoped s3", RefKind.Ref, DeclarationScope.Unscoped); - VerifyLocalSymbol(locals[3], "scoped scoped s4", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[4], "scoped ref scoped s5", RefKind.Ref, DeclarationScope.RefScoped); - VerifyLocalSymbol(locals[5], "scoped ref scoped s6", RefKind.Ref, DeclarationScope.RefScoped); + VerifyLocalSymbol(locals[0], "scoped s1", RefKind.None, ScopedKind.None); + VerifyLocalSymbol(locals[1], "ref scoped s2", RefKind.Ref, ScopedKind.None); + VerifyLocalSymbol(locals[2], "ref scoped s3", RefKind.Ref, ScopedKind.None); + VerifyLocalSymbol(locals[3], "scoped scoped s4", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[4], "scoped ref scoped s5", RefKind.Ref, ScopedKind.ScopedRef); + VerifyLocalSymbol(locals[5], "scoped ref scoped s6", RefKind.Ref, ScopedKind.ScopedRef); } } @@ -25415,12 +26508,12 @@ static void verify(CSharpCompilation comp) var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol()).ToArray(); - VerifyLocalSymbol(locals[0], "scoped s1", RefKind.None, DeclarationScope.Unscoped); - VerifyLocalSymbol(locals[1], "ref scoped s2", RefKind.Ref, DeclarationScope.Unscoped); - VerifyLocalSymbol(locals[2], "ref scoped s3", RefKind.Ref, DeclarationScope.Unscoped); - VerifyLocalSymbol(locals[3], "scoped scoped s4", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[4], "scoped ref scoped s5", RefKind.Ref, DeclarationScope.RefScoped); - VerifyLocalSymbol(locals[5], "scoped ref scoped s6", RefKind.Ref, DeclarationScope.RefScoped); + VerifyLocalSymbol(locals[0], "scoped s1", RefKind.None, ScopedKind.None); + VerifyLocalSymbol(locals[1], "ref scoped s2", RefKind.Ref, ScopedKind.None); + VerifyLocalSymbol(locals[2], "ref scoped s3", RefKind.Ref, ScopedKind.None); + VerifyLocalSymbol(locals[3], "scoped scoped s4", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[4], "scoped ref scoped s5", RefKind.Ref, ScopedKind.ScopedRef); + VerifyLocalSymbol(locals[5], "scoped ref scoped s6", RefKind.Ref, ScopedKind.ScopedRef); } } @@ -25466,8 +26559,8 @@ static void verifyModel(CSharpCompilation comp) Assert.Equal("R", local.Type.ToTestDisplayString()); } - VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[1], "scoped R r3", RefKind.None, DeclarationScope.ValueScoped); + VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[1], "scoped R r3", RefKind.None, ScopedKind.ScopedValue); foreach (var decl in decls) { @@ -25526,8 +26619,8 @@ static void verifyModel(CSharpCompilation comp) Assert.Equal("R", local.Type.ToTestDisplayString()); } - VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[1], "scoped R r3", RefKind.None, DeclarationScope.ValueScoped); + VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[1], "scoped R r3", RefKind.None, ScopedKind.ScopedValue); foreach (var decl in decls) { @@ -25750,8 +26843,8 @@ static void verify(CSharpCompilation comp) var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol()).ToArray(); - VerifyLocalSymbol(locals[0], "scoped R r2", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[1], "scoped R r5", RefKind.None, DeclarationScope.ValueScoped); + VerifyLocalSymbol(locals[0], "scoped R r2", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[1], "scoped R r5", RefKind.None, ScopedKind.ScopedValue); var type = ((VariableDeclarationSyntax)decls[0].Parent).Type; Assert.Null(model.GetTypeInfo(type).Type); @@ -25798,8 +26891,8 @@ static void verify(CSharpCompilation comp) var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol()).ToArray(); - VerifyLocalSymbol(locals[0], "scoped R r2", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[1], "scoped R r5", RefKind.None, DeclarationScope.ValueScoped); + VerifyLocalSymbol(locals[0], "scoped R r2", RefKind.None, ScopedKind.ScopedValue); + VerifyLocalSymbol(locals[1], "scoped R r5", RefKind.None, ScopedKind.ScopedValue); var type = ((VariableDeclarationSyntax)decls[0].Parent).Type; Assert.Null(model.GetTypeInfo(type).Type); @@ -26350,6 +27443,37 @@ public RefByteContainer Create(ref ByteContainer bc) comp.VerifyDiagnostics(); } + [Fact, WorkItem(63526, "https://github.com/dotnet/roslyn/issues/63526")] + public void ReturnOnlyScope_UnsafeStatement() + { + var source = """ + #pragma warning disable 8321 // unused local function + static void M1(scoped ref S p1, ref S p2, ref S p3) + { + unsafe + { + p2.refField = ref p1.field; // 1 + } + { + p3.refField = ref p1.field; // 2 + } + } + ref struct S + { + public int field; + public ref int refField; + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70, options: TestOptions.UnsafeReleaseExe); + comp.VerifyDiagnostics( + // (6,9): warning CS9085: This ref-assigns 'p1.field' to 'refField' but 'p1.field' has a narrower escape scope than 'refField'. + // p2.refField = ref p1.field; // 1 + Diagnostic(ErrorCode.WRN_RefAssignNarrower, "p2.refField = ref p1.field").WithArguments("refField", "p1.field").WithLocation(6, 9), + // (9,9): error CS8374: Cannot ref-assign 'p1.field' to 'refField' because 'p1.field' has a narrower escape scope than 'refField'. + // p3.refField = ref p1.field; // 1 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "p3.refField = ref p1.field").WithArguments("refField", "p1.field").WithLocation(9, 9)); + } + /// /// Validate that this is properly represented as an out parameter in a constructor and /// can capture ref as ref. @@ -26764,9 +27888,9 @@ public R() { } // (4,37): error CS8347: Cannot use a result of 'R.F(in Span)' in this context because it may expose variables referenced by parameter 's' outside of their declaration scope // ref readonly Span _s = ref F(stackalloc int[1]); Diagnostic(ErrorCode.ERR_EscapeCall, "F(stackalloc int[1])").WithArguments("R.F(in System.Span)", "s").WithLocation(4, 37), - // (4,39): error CS8353: A result of a stackalloc expression of type 'Span' cannot be used in this context because it may be exposed outside of the containing method + // (4,39): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference // ref readonly Span _s = ref F(stackalloc int[1]); - Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc int[1]").WithArguments("System.Span").WithLocation(4, 39)); + Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "stackalloc int[1]").WithLocation(4, 39)); } [WorkItem(64720, "https://github.com/dotnet/roslyn/issues/64720")] @@ -26968,29 +28092,127 @@ .maxstack 2 controlFlowGraph, symbol); } - [Fact, WorkItem(64045, "https://github.com/dotnet/roslyn/issues/64045")] - public void ConstructorInvocationValEscape_01() + [Fact] + [WorkItem(63565, "https://github.com/dotnet/roslyn/issues/63565")] + public void UnscopedRefAttribute_DelegateConversion_01() { - var source = """ + string source = """ + using System.Diagnostics.CodeAnalysis; + ref struct R { } class Program { - static RS M1(scoped ref int i1) => new(ref i1); - static RS M2(scoped ref int i2) + static void Main() { - return new(ref i2); + var a = ([UnscopedRef] ref int x1, ref int y1) => ref y1; + var b = ([UnscopedRef] ref int x2, R y2) => y2; + var c = ([UnscopedRef] ref int x3, ref R y3) => { }; + var d = ([UnscopedRef] out int x4) => { x4 = 0; return ref x4; }; + var e = ([UnscopedRef] ref int x5) => x5; + var f = ([UnscopedRef] ref int x6) => ref x6; + var g = ref readonly int ([UnscopedRef] in int x7) => ref x7; } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics(); + } - static RS M3(scoped ref int i3) => new RS(ref i3); - static RS M4(scoped ref int i4) + [Fact] + [WorkItem(63565, "https://github.com/dotnet/roslyn/issues/63565")] + public void UnscopedRefAttribute_DelegateConversion_02() + { + string source = """ + using System.Diagnostics.CodeAnalysis; + ref struct R { } + class Program + { + static ref int F1(ref int y1, [UnscopedRef] ref int x1) => ref y1; + static R F2(R y2, [UnscopedRef] ref int x2) => y2; + static void F3(ref R y3, [UnscopedRef] ref int x3) { } + static ref int F4([UnscopedRef] out int x4) { x4 = 0; return ref x4; } + static int F5([UnscopedRef] ref int x5) => x5; + static ref int F6([UnscopedRef] ref int x6) => ref x6; + static ref readonly int F7([UnscopedRef] in int x7) => ref x7; + static void Main() { - return new RS(ref i4); + var a = F1; + var b = F2; + var c = F3; + var d = F4; + var e = F5; + var f = F6; + var g = F7; } } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics(); + } - ref struct RS + [Fact] + [WorkItem(63565, "https://github.com/dotnet/roslyn/issues/63565")] + public void UnscopedRefAttribute_DelegateConversion_03() + { + string source = """ + using System.Diagnostics.CodeAnalysis; + class Program { - public RS(ref int i0) => throw null!; - } + static ref int F1(ref int x, ref int y) => ref x; + static ref int F2(ref int x, [UnscopedRef] ref int y) => ref x; + static ref int F3([UnscopedRef] ref int x, [UnscopedRef] ref int y) => ref x; + static void Main() + { + var d1 = F1; + var d2 = F2; + var d3 = F3; + d1 = F2; // 1 + d1 = F3; // 2, 3 + d2 = F1; + d2 = F3; // 4 + d3 = F1; + d2 = F2; + } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics( + // (12,14): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target ''. + // d1 = F2; // 1 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "F2").WithArguments("y", "").WithLocation(12, 14), + // (13,14): error CS8986: The 'scoped' modifier of parameter 'x' doesn't match target ''. + // d1 = F3; // 2, 3 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "F3").WithArguments("x", "").WithLocation(13, 14), + // (13,14): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target ''. + // d1 = F3; // 2, 3 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "F3").WithArguments("y", "").WithLocation(13, 14), + // (15,14): error CS8986: The 'scoped' modifier of parameter 'x' doesn't match target ''. + // d2 = F3; // 4 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "F3").WithArguments("x", "").WithLocation(15, 14)); + } + + [Fact, WorkItem(64045, "https://github.com/dotnet/roslyn/issues/64045")] + public void ConstructorInvocationValEscape_01() + { + var source = """ + class Program + { + static RS M1(scoped ref int i1) => new(ref i1); + static RS M2(scoped ref int i2) + { + return new(ref i2); + } + + static RS M3(scoped ref int i3) => new RS(ref i3); + static RS M4(scoped ref int i4) + { + return new RS(ref i4); + } + } + + ref struct RS + { + public RS(ref int i0) => throw null!; + } """; var comp = CreateCompilation(source); comp.VerifyDiagnostics( @@ -27076,5 +28298,981 @@ ref struct RS // return new RS(ref i4); // 4 Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "i4").WithArguments("i4").WithLocation(14, 31)); } + + [Fact, WorkItem(65648, "https://github.com/dotnet/roslyn/issues/65648")] + public void ReturnRefToRefStruct_ValEscape_01() + { + var source = """ + using System.Diagnostics.CodeAnalysis; + + public class Repro + { + private static void Bad1(int value) + { + RefStruct s1 = new RefStruct(); + s1.RefField = ref value; // 1 + } + + private static void Bad2(int value) + { + RefStruct s1 = new RefStruct(); + s1.RefProperty.RefField = ref value; // 2 + } + + private static void Bad3(int value) + { + RefStruct s1 = new RefStruct(); + s1.RefMethod().RefField = ref value; // 3 + } + + private ref struct RefStruct + { + public ref int RefField; + [UnscopedRef] public ref RefStruct RefProperty => ref this; + [UnscopedRef] public ref RefStruct RefMethod() => ref this; + } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyDiagnostics( + // (8,9): error CS8374: Cannot ref-assign 'value' to 'RefField' because 'value' has a narrower escape scope than 'RefField'. + // s1.RefField = ref value; // 1 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "s1.RefField = ref value").WithArguments("RefField", "value").WithLocation(8, 9), + // (14,9): error CS8374: Cannot ref-assign 'value' to 'RefField' because 'value' has a narrower escape scope than 'RefField'. + // s1.RefProperty.RefField = ref value; // 2 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "s1.RefProperty.RefField = ref value").WithArguments("RefField", "value").WithLocation(14, 9), + // (20,9): error CS8374: Cannot ref-assign 'value' to 'RefField' because 'value' has a narrower escape scope than 'RefField'. + // s1.RefMethod().RefField = ref value; // 3 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "s1.RefMethod().RefField = ref value").WithArguments("RefField", "value").WithLocation(20, 9)); + } + + [Fact, WorkItem(65648, "https://github.com/dotnet/roslyn/issues/65648")] + public void ReturnRefToRefStruct_ValEscape_02() + { + var source = """ + using System.Diagnostics.CodeAnalysis; + + public class Repro + { + private static void Bad1(scoped ref RefStruct s1, int value) + { + s1.RefField = ref value; // 1 + } + + private static void Bad2(scoped ref RefStruct s1, int value) + { + s1.RefProperty.RefField = ref value; // 2 + } + + private static void Bad3(scoped ref RefStruct s1, int value) + { + s1.RefMethod().RefField = ref value; // 3 + } + + private static void Bad4(scoped in RefStruct s1, int value) + { + s1.RefField = ref value; // 4 + } + + private static void Bad5(scoped in RefStruct s1, int value) + { + s1.RefProperty.RefField = ref value; // 5 + } + + private static void Bad6(scoped in RefStruct s1, int value) + { + s1.RefMethod().RefField = ref value; // 6 + } + + private static void Bad7(in RefStruct s1, int value) + { + s1.RefField = ref value; // 7 + } + + private static void Bad8(in RefStruct s1, int value) + { + s1.RefProperty.RefField = ref value; // 8 + } + + private static void Bad9(in RefStruct s1, int value) + { + s1.RefMethod().RefField = ref value; // 9 + } + + private ref struct RefStruct + { + public ref int RefField; + [UnscopedRef] public ref RefStruct RefProperty => ref this; + [UnscopedRef] public ref RefStruct RefMethod() => ref this; + } + } + """; + + // NB: 8 and 9 are not strictly necessary here because they are assigning to an implicit copy of a readonly variable, not to the original variable. + // However, it is not deeply problematic that an error is given here. + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyDiagnostics( + // (7,9): error CS8374: Cannot ref-assign 'value' to 'RefField' because 'value' has a narrower escape scope than 'RefField'. + // s1.RefField = ref value; // 1 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "s1.RefField = ref value").WithArguments("RefField", "value").WithLocation(7, 9), + // (12,9): error CS8374: Cannot ref-assign 'value' to 'RefField' because 'value' has a narrower escape scope than 'RefField'. + // s1.RefProperty.RefField = ref value; // 2 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "s1.RefProperty.RefField = ref value").WithArguments("RefField", "value").WithLocation(12, 9), + // (17,9): error CS8374: Cannot ref-assign 'value' to 'RefField' because 'value' has a narrower escape scope than 'RefField'. + // s1.RefMethod().RefField = ref value; // 3 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "s1.RefMethod().RefField = ref value").WithArguments("RefField", "value").WithLocation(17, 9), + // (22,9): error CS8332: Cannot assign to a member of variable 's1' or use it as the right hand side of a ref assignment because it is a readonly variable + // s1.RefField = ref value; // 4 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField2, "s1.RefField").WithArguments("variable", "s1").WithLocation(22, 9), + // (27,9): error CS8374: Cannot ref-assign 'value' to 'RefField' because 'value' has a narrower escape scope than 'RefField'. + // s1.RefProperty.RefField = ref value; // 5 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "s1.RefProperty.RefField = ref value").WithArguments("RefField", "value").WithLocation(27, 9), + // (32,9): error CS8374: Cannot ref-assign 'value' to 'RefField' because 'value' has a narrower escape scope than 'RefField'. + // s1.RefMethod().RefField = ref value; // 6 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "s1.RefMethod().RefField = ref value").WithArguments("RefField", "value").WithLocation(32, 9), + // (37,9): error CS8332: Cannot assign to a member of variable 's1' or use it as the right hand side of a ref assignment because it is a readonly variable + // s1.RefField = ref value; // 7 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField2, "s1.RefField").WithArguments("variable", "s1").WithLocation(37, 9), + // (42,9): error CS8374: Cannot ref-assign 'value' to 'RefField' because 'value' has a narrower escape scope than 'RefField'. + // s1.RefProperty.RefField = ref value; // 8 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "s1.RefProperty.RefField = ref value").WithArguments("RefField", "value").WithLocation(42, 9), + // (47,9): error CS8374: Cannot ref-assign 'value' to 'RefField' because 'value' has a narrower escape scope than 'RefField'. + // s1.RefMethod().RefField = ref value; // 9 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "s1.RefMethod().RefField = ref value").WithArguments("RefField", "value").WithLocation(47, 9)); + } + + [Fact, WorkItem(65648, "https://github.com/dotnet/roslyn/issues/65648")] + public void ReturnRefToRefStruct_ValEscape_03() + { + var source = """ + using System.Diagnostics.CodeAnalysis; + + public class Repro + { + private static void Bad1(ref RefStruct s1, int value) + { + s1 = new RefStruct(ref value); // 1 + } + + private static void Bad2(scoped ref RefStruct s1, int value) + { + s1.RefProperty = new RefStruct(ref value); // 2 + } + + private static void Bad3(scoped ref RefStruct s1, int value) + { + s1.RefMethod() = new RefStruct(ref value); // 3 + } + + private static void Bad4(scoped ref RefStruct s1, int value) + { + GetRef(ref s1) = new RefStruct(ref value); // 4 + } + + private static ref RefStruct GetRef(ref RefStruct s) => ref s; + + private ref struct RefStruct + { + public RefStruct(ref int i) => RefField = ref i; + public ref int RefField; + [UnscopedRef] public ref RefStruct RefProperty => ref this; + [UnscopedRef] public ref RefStruct RefMethod() => ref this; + } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyDiagnostics( + // (7,14): error CS8347: Cannot use a result of 'Repro.RefStruct.RefStruct(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope + // s1 = new RefStruct(ref value); // 1 + Diagnostic(ErrorCode.ERR_EscapeCall, "new RefStruct(ref value)").WithArguments("Repro.RefStruct.RefStruct(ref int)", "i").WithLocation(7, 14), + // (7,32): error CS8166: Cannot return a parameter by reference 'value' because it is not a ref parameter + // s1 = new RefStruct(ref value); // 1 + Diagnostic(ErrorCode.ERR_RefReturnParameter, "value").WithArguments("value").WithLocation(7, 32), + // (12,26): error CS8347: Cannot use a result of 'Repro.RefStruct.RefStruct(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope + // s1.RefProperty = new RefStruct(ref value); // 2 + Diagnostic(ErrorCode.ERR_EscapeCall, "new RefStruct(ref value)").WithArguments("Repro.RefStruct.RefStruct(ref int)", "i").WithLocation(12, 26), + // (12,44): error CS8166: Cannot return a parameter by reference 'value' because it is not a ref parameter + // s1.RefProperty = new RefStruct(ref value); // 2 + Diagnostic(ErrorCode.ERR_RefReturnParameter, "value").WithArguments("value").WithLocation(12, 44), + // (17,26): error CS8347: Cannot use a result of 'Repro.RefStruct.RefStruct(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope + // s1.RefMethod() = new RefStruct(ref value); // 3 + Diagnostic(ErrorCode.ERR_EscapeCall, "new RefStruct(ref value)").WithArguments("Repro.RefStruct.RefStruct(ref int)", "i").WithLocation(17, 26), + // (17,44): error CS8166: Cannot return a parameter by reference 'value' because it is not a ref parameter + // s1.RefMethod() = new RefStruct(ref value); // 3 + Diagnostic(ErrorCode.ERR_RefReturnParameter, "value").WithArguments("value").WithLocation(17, 44), + // (22,26): error CS8347: Cannot use a result of 'Repro.RefStruct.RefStruct(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope + // GetRef(ref s1) = new RefStruct(ref value); // 4 + Diagnostic(ErrorCode.ERR_EscapeCall, "new RefStruct(ref value)").WithArguments("Repro.RefStruct.RefStruct(ref int)", "i").WithLocation(22, 26), + // (22,44): error CS8166: Cannot return a parameter by reference 'value' because it is not a ref parameter + // GetRef(ref s1) = new RefStruct(ref value); // 4 + Diagnostic(ErrorCode.ERR_RefReturnParameter, "value").WithArguments("value").WithLocation(22, 44)); + } + + [Fact, WorkItem(65648, "https://github.com/dotnet/roslyn/issues/65648")] + public void ReturnRefToRefStruct_ValEscape_04() + { + // test that the appropriate filtering of escape-values is occurring when the RTRS expression is on the RHS of an an assignment. + var source = """ + using System.Diagnostics.CodeAnalysis; + + public class Repro + { + private static void M1(ref RefStruct s1, int value) + { + // 's2' only contributes STE, not RSTE, to the STE of 'RefMethod()' invocation. + // STE is equal to RSTE for 's2', so it doesn't matter. + var s2 = new RefStruct(ref value); + s1 = s2.RefMethod(); // 1 + } + + private static void M2(ref RefStruct s1, ref RefStruct s2) + { + // 's2' only contributes STE, not RSTE, to the STE of 'RefMethod()' invocation. + // RSTE of `s2` is narrower than STE of 's1', but STE of 's2' equals STE of 's1', so we expect no error here. + s1 = s2.RefMethod(); + } + + private ref struct RefStruct + { + public RefStruct(ref int i) => RefField = ref i; + public ref int RefField; + [UnscopedRef] public ref RefStruct RefMethod() => ref this; + } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyDiagnostics( + // (10,14): error CS8352: Cannot use variable 's2' in this context because it may expose referenced variables outside of their declaration scope + // s1 = s2.RefMethod(); // 1 + Diagnostic(ErrorCode.ERR_EscapeVariable, "s2").WithArguments("s2").WithLocation(10, 14)); + } + + [Fact, WorkItem(65648, "https://github.com/dotnet/roslyn/issues/65648")] + public void ReturnRefToRefStruct_RefEscape_01() + { + var source = """ + public class Repro + { + private static ref RefStruct M1(ref RefStruct s1, ref RefStruct s2) + { + bool b = false; + return ref b ? ref s1 : ref s2; + } + + private static ref RefStruct M2(ref RefStruct s1) + { + RefStruct s2 = default; + // RSTE of s1 is ReturnOnly + // RSTE of s2 is CurrentMethod + return ref M1(ref s1, ref s2); // 1 + } + + private static ref RefStruct M3(ref RefStruct s1) + { + return ref M1(ref s1, ref s1); + } + + private ref struct RefStruct { } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyDiagnostics( + // (14,20): error CS8347: Cannot use a result of 'Repro.M1(ref Repro.RefStruct, ref Repro.RefStruct)' in this context because it may expose variables referenced by parameter 's2' outside of their declaration scope + // return ref M1(ref s1, ref s2); // 1 + Diagnostic(ErrorCode.ERR_EscapeCall, "M1(ref s1, ref s2)").WithArguments("Repro.M1(ref Repro.RefStruct, ref Repro.RefStruct)", "s2").WithLocation(14, 20), + // (14,35): error CS8168: Cannot return local 's2' by reference because it is not a ref local + // return ref M1(ref s1, ref s2); // 1 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "s2").WithArguments("s2").WithLocation(14, 35) + ); + } + + [Fact, WorkItem(65648, "https://github.com/dotnet/roslyn/issues/65648")] + public void ReturnRefToRefStruct_RefEscape_BothScopedAndUnscopedRefParameters() + { + var source = """ + public class Repro + { + private static ref RefStruct M1(ref RefStruct s1, scoped ref RefStruct s2) + { + return ref s1; + } + + private static ref RefStruct M2(ref RefStruct s1) + { + RefStruct s2 = default; + // RSTE of s1 is ReturnOnly + // RSTE of s2 is CurrentMethod, but it doesn't contribute to RSTE of the invocation. + return ref M1(ref s1, ref s2); + } + + private static ref RefStruct M3(ref RefStruct s1) + { + return ref M1(ref s1, ref s1); + } + + private ref struct RefStruct { } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyDiagnostics(); + } + + [Fact, WorkItem(65648, "https://github.com/dotnet/roslyn/issues/65648")] + public void ReturnRefToRefStruct_RefEscape_02() + { + var source = """ + public class Repro + { + private static ref RefStruct M1(ref RefStruct s1, RefStruct s2) + { + return ref s1; + } + + private static ref RefStruct M2(ref RefStruct s1, int param) + { + RefStruct s2 = new RefStruct(ref param); + // RSTE of s1 is ReturnOnly + // STE of s2 is CurrentMethod, but this is not contributed to the call to M1. + // We error due to arg mixing, not due to the return value. + return ref M1(ref s1, s2); + } + + private ref struct RefStruct + { + public RefStruct(ref int i) { } + } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyDiagnostics( + // (14,20): error CS8350: This combination of arguments to 'Repro.M1(ref Repro.RefStruct, Repro.RefStruct)' is disallowed because it may expose variables referenced by parameter 's2' outside of their declaration scope + // return ref M1(ref s1, s2); + Diagnostic(ErrorCode.ERR_CallArgMixing, "M1(ref s1, s2)").WithArguments("Repro.M1(ref Repro.RefStruct, Repro.RefStruct)", "s2").WithLocation(14, 20), + // (14,31): error CS8352: Cannot use variable 's2' in this context because it may expose referenced variables outside of their declaration scope + // return ref M1(ref s1, s2); + Diagnostic(ErrorCode.ERR_EscapeVariable, "s2").WithArguments("s2").WithLocation(14, 31) + ); + } + + [Fact, WorkItem(65648, "https://github.com/dotnet/roslyn/issues/65648")] + public void ReturnRefToRefStruct_VariousInputAndOutputRefKinds() + { + var source = """ + using System.Diagnostics.CodeAnalysis; + + public class Repro + { + private static void Bad1(int value) + { + RefStruct s1 = new RefStruct(); + GetReference1(ref s1).RefField = ref value; // 1 + GetReference2(in s1).RefField = ref value; // 2 + GetReference3(out s1).RefField = ref value; // 3 + + GetReadonlyReference1(ref s1).RefField = ref value; // 4 + GetReadonlyReference2(in s1).RefField = ref value; // 5 + GetReadonlyReference3(out s1).RefField = ref value; // 6 + } + + static ref RefStruct GetReference1(ref RefStruct rs) => throw null!; + static ref RefStruct GetReference2(in RefStruct rs) => throw null!; + static ref RefStruct GetReference3([UnscopedRef] out RefStruct rs) => throw null!; + + static ref readonly RefStruct GetReadonlyReference1(ref RefStruct rs) => throw null!; + static ref readonly RefStruct GetReadonlyReference2(in RefStruct rs) => throw null!; + static ref readonly RefStruct GetReadonlyReference3([UnscopedRef] out RefStruct rs) => throw null!; + + private ref struct RefStruct + { + public ref int RefField; + } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyDiagnostics( + // (8,9): error CS8374: Cannot ref-assign 'value' to 'RefField' because 'value' has a narrower escape scope than 'RefField'. + // GetReference1(ref s1).RefField = ref value; // 1 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "GetReference1(ref s1).RefField = ref value").WithArguments("RefField", "value").WithLocation(8, 9), + // (9,9): error CS8374: Cannot ref-assign 'value' to 'RefField' because 'value' has a narrower escape scope than 'RefField'. + // GetReference2(in s1).RefField = ref value; // 2 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "GetReference2(in s1).RefField = ref value").WithArguments("RefField", "value").WithLocation(9, 9), + // (10,9): error CS8374: Cannot ref-assign 'value' to 'RefField' because 'value' has a narrower escape scope than 'RefField'. + // GetReference3(out s1).RefField = ref value; // 3 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "GetReference3(out s1).RefField = ref value").WithArguments("RefField", "value").WithLocation(10, 9), + // (12,9): error CS8332: Cannot assign to a member of method 'GetReadonlyReference1' or use it as the right hand side of a ref assignment because it is a readonly variable + // GetReadonlyReference1(ref s1).RefField = ref value; // 4 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField2, "GetReadonlyReference1(ref s1).RefField").WithArguments("method", "GetReadonlyReference1").WithLocation(12, 9), + // (13,9): error CS8332: Cannot assign to a member of method 'GetReadonlyReference2' or use it as the right hand side of a ref assignment because it is a readonly variable + // GetReadonlyReference2(in s1).RefField = ref value; // 5 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField2, "GetReadonlyReference2(in s1).RefField").WithArguments("method", "GetReadonlyReference2").WithLocation(13, 9), + // (14,9): error CS8332: Cannot assign to a member of method 'GetReadonlyReference3' or use it as the right hand side of a ref assignment because it is a readonly variable + // GetReadonlyReference3(out s1).RefField = ref value; // 6 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField2, "GetReadonlyReference3(out s1).RefField").WithArguments("method", "GetReadonlyReference3").WithLocation(14, 9)); + } + + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void ConstructorInitializer_01(LanguageVersion languageVersion) + { + var source = """ + using System; + class A + { + public A(ref Span x, Span y) { } + A(ref Span s) : this(ref s, new Span()) { } + A(ref Span s, int i) : this(ref s, stackalloc int[1]) { } // 1 + } + class B : A + { + B(ref Span s) : base(ref s, new Span()) { } + B(ref Span s, int i) : base(ref s, stackalloc int[2]) { } // 2 + } + """; + var comp = CreateCompilationWithSpan(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyDiagnostics( + // (6,31): error CS8350: This combination of arguments to 'A.A(ref Span, Span)' is disallowed because it may expose variables referenced by parameter 'y' outside of their declaration scope + // A(ref Span s, int i) : this(ref s, stackalloc int[1]) { } // 1 + Diagnostic(ErrorCode.ERR_CallArgMixing, ": this(ref s, stackalloc int[1])").WithArguments("A.A(ref System.Span, System.Span)", "y").WithLocation(6, 31), + // (6,45): error CS8353: A result of a stackalloc expression of type 'Span' cannot be used in this context because it may be exposed outside of the containing method + // A(ref Span s, int i) : this(ref s, stackalloc int[1]) { } // 1 + Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc int[1]").WithArguments("System.Span").WithLocation(6, 45), + // (11,31): error CS8350: This combination of arguments to 'A.A(ref Span, Span)' is disallowed because it may expose variables referenced by parameter 'y' outside of their declaration scope + // B(ref Span s, int i) : base(ref s, stackalloc int[2]) { } // 2 + Diagnostic(ErrorCode.ERR_CallArgMixing, ": base(ref s, stackalloc int[2])").WithArguments("A.A(ref System.Span, System.Span)", "y").WithLocation(11, 31), + // (11,45): error CS8353: A result of a stackalloc expression of type 'Span' cannot be used in this context because it may be exposed outside of the containing method + // B(ref Span s, int i) : base(ref s, stackalloc int[2]) { } // 2 + Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc int[2]").WithArguments("System.Span").WithLocation(11, 45)); + } + + [Fact] + public void ConstructorInitializer_02() + { + var source = """ + ref struct R + { + R(in int i) { } + R(int x, int y) : this(x) { } // 1 + } + """; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (4,21): error CS8350: This combination of arguments to 'R.R(in int)' is disallowed because it may expose variables referenced by parameter 'i' outside of their declaration scope + // R(int x, int y) : this(x) { } // 1 + Diagnostic(ErrorCode.ERR_CallArgMixing, ": this(x)").WithArguments("R.R(in int)", "i").WithLocation(4, 21), + // (4,28): error CS8166: Cannot return a parameter by reference 'x' because it is not a ref parameter + // R(int x, int y) : this(x) { } // 1 + Diagnostic(ErrorCode.ERR_RefReturnParameter, "x").WithArguments("x").WithLocation(4, 28)); + } + + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void FunctionPointerInvocation_01(LanguageVersion languageVersion) + { + var source = """ + using System; + class Program + { + static void F0(ref Span x, Span y) + { + } + static unsafe void F1(ref Span s) + { + delegate*, Span, void> f = &F0; + f(ref s, new Span()); + f(ref s, stackalloc int[1]); // 1 + } + } + """; + var comp = CreateCompilationWithSpan(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), options: TestOptions.UnsafeReleaseDll); + comp.VerifyDiagnostics( + // (11,18): warning CS9081: A result of a stackalloc expression of type 'Span' in this context may be exposed outside of the containing method + // f(ref s, stackalloc int[1]); // 1 + Diagnostic(ErrorCode.WRN_EscapeStackAlloc, "stackalloc int[1]").WithArguments("System.Span").WithLocation(11, 18)); + } + + [Fact] + public void FunctionPointerInvocation_02() + { + var source = """ + ref struct R + { + } + class Program + { + static void F0(out R r, in int i) + { + r = default; + } + static unsafe void F1(out R r1, in int i1) + { + delegate* f = &F0; + f(out r1, i1); + } + static unsafe void F2(out R r1, int i2) + { + delegate* f = &F0; + f(out r1, i2); // 1 + } + } + """; + var comp = CreateCompilationWithSpan(source, options: TestOptions.UnsafeReleaseDll); + comp.VerifyDiagnostics( + // (18,19): warning CS9087: This returns a parameter by reference 'i2' but it is not a ref parameter + // f(out r1, i2); // 1 + Diagnostic(ErrorCode.WRN_RefReturnParameter, "i2").WithArguments("i2").WithLocation(18, 19)); + } + + [Fact] + public void PatternIndex_01() + { + string source = """ + using System; + using System.Diagnostics.CodeAnalysis; + ref struct R + { + public int Length => 0; + [UnscopedRef] public ref int this[int i] => throw null; + } + class Program + { + static ref int F1(ref R r1) + { + ref int i1 = ref r1[^1]; + return ref i1; + } + static ref int F2(ref R r2, Index i) + { + ref int i2 = ref r2[i]; + return ref i2; + } + static ref int F3() + { + R r3 = new R(); + ref int i3 = ref r3[^3]; + return ref i3; // 1 + } + static ref int F4(Index i) + { + R r4 = new R(); + ref int i4 = ref r4[i]; + return ref i4; // 2 + } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyDiagnostics( + // (24,20): error CS8157: Cannot return 'i3' by reference because it was initialized to a value that cannot be returned by reference + // return ref i3; // 1 + Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "i3").WithArguments("i3").WithLocation(24, 20), + // (30,20): error CS8157: Cannot return 'i4' by reference because it was initialized to a value that cannot be returned by reference + // return ref i4; // 2 + Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "i4").WithArguments("i4").WithLocation(30, 20)); + } + + [Fact] + public void PatternIndex_02() + { + string source = """ + ref struct R + { + public R(ref int i) { } + public int Length => 0; + public R this[int i] => throw null; + } + class Program + { + static R F1() + { + R r1 = new R(); + if (r1 is [.., var r]) return r; + return r1; + } + static R F2() + { + int i2 = 2; + R r2 = new R(ref i2); + if (r2 is [.., var r]) return r; // 1 + return r2; // 2 + } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyDiagnostics( + // (19,39): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope + // if (r2 is [.., var r]) return r; // 1 + Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(19, 39), + // (20,16): error CS8352: Cannot use variable 'r2' in this context because it may expose referenced variables outside of their declaration scope + // return r2; // 2 + Diagnostic(ErrorCode.ERR_EscapeVariable, "r2").WithArguments("r2").WithLocation(20, 16)); + } + + [Fact] + public void PatternIndex_03() + { + string source = """ + ref struct R + { + public R(ref int i) { } + public int Length => 0; + public int this[int i] => 0; + public R Slice(int x, int y) => this; + } + class Program + { + static R F1() + { + R r1 = new R(); + if (r1 is [.. [> 0] r]) return r; + return r1; + } + static R F2() + { + int i2 = 2; + R r2 = new R(ref i2); + if (r2 is [.. [> 0] r]) return r; // 1 + return r2; // 2 + } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyDiagnostics( + // (20,40): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope + // if (r2 is [.. [> 0] r]) return r; // 1 + Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(20, 40), + // (21,16): error CS8352: Cannot use variable 'r2' in this context because it may expose referenced variables outside of their declaration scope + // return r2; // 2 + Diagnostic(ErrorCode.ERR_EscapeVariable, "r2").WithArguments("r2").WithLocation(21, 16)); + } + + [Fact] + public void TopLevelStatementLocal() + { + var source = """ + int i = 0; + ref int r = ref i; + class C + { + static void F1() { F2(ref r); } + static ref int F2(ref int r) => ref r; + } + """; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (5,31): error CS8801: Cannot use local variable or local function 'r' declared in a top-level statement in this context. + // static void F1() { F2(ref r); } + Diagnostic(ErrorCode.ERR_SimpleProgramLocalIsReferencedOutsideOfTopLevelStatement, "r").WithArguments("r").WithLocation(5, 31), + // (5,31): error CS0165: Use of unassigned local variable 'r' + // static void F1() { F2(ref r); } + Diagnostic(ErrorCode.ERR_UseDefViolation, "r").WithArguments("r").WithLocation(5, 31)); + } + + [Fact] + public void Discard_01() + { + var source = """ + class Program + { + static ref int F1() + { + return ref F2(out _); + } + static ref int F2(out int i) + { + i = 0; + return ref i; + } + } + """; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics( + // (5,20): error CS8347: Cannot use a result of 'Program.F2(out int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope + // return ref F2(out _); + Diagnostic(ErrorCode.ERR_EscapeCall, "F2(out _)").WithArguments("Program.F2(out int)", "i").WithLocation(5, 20), + // (5,27): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference + // return ref F2(out _); + Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "_").WithLocation(5, 27)); + } + + [Fact] + public void Discard_02() + { + var source = """ + using System.Diagnostics.CodeAnalysis; + class Program + { + static ref int F1() + { + return ref F2(out _); + } + static ref int F2([UnscopedRef] out int i) + { + i = 0; + return ref i; + } + } + """; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics( + // (6,20): error CS8347: Cannot use a result of 'Program.F2(out int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope + // return ref F2(out _); + Diagnostic(ErrorCode.ERR_EscapeCall, "F2(out _)").WithArguments("Program.F2(out int)", "i").WithLocation(6, 20), + // (6,27): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference + // return ref F2(out _); + Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "_").WithLocation(6, 27)); + } + + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void Discard_03(LanguageVersion languageVersion) + { + var source = """ + ref struct R + { + public void Deconstruct(out int x, out R y) + { + x = 0; + y = default; + } + } + class Program + { + static R F1() + { + R r1 = default; + int i; + (i, _) = r1; + return r1; + } + static R F2() + { + R r2 = default; + int i; + r2.Deconstruct(out i, out _); + return r2; + } + } + """; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyDiagnostics(); + } + + [Fact] + public void SwitchExpression_Assignment() + { + var source = """ + using System; + class Program + { + static void M() + { + Span s; + Span outer = stackalloc int[100]; + s = outer switch + { + Span inner => inner + }; + } + } + """; + var comp = CreateCompilationWithSpan(source); + comp.VerifyDiagnostics( + // (10,32): error CS8352: Cannot use variable 'inner' in this context because it may expose referenced variables outside of their declaration scope + // Span inner => inner + Diagnostic(ErrorCode.ERR_EscapeVariable, "inner").WithArguments("inner").WithLocation(10, 32)); + } + + [Fact] + public void SwitchExpression_Argument() + { + var source = """ + using System; + class Program + { + static Span F(Span x, Span y) + { + return x; + } + static void M() + { + Span x = default; + Span y = stackalloc int[100]; + x = F(x, y switch { Span inner => inner }); + } + } + """; + var comp = CreateCompilationWithSpan(source); + comp.VerifyDiagnostics( + // (12,13): error CS8347: Cannot use a result of 'Program.F(Span, Span)' in this context because it may expose variables referenced by parameter 'y' outside of their declaration scope + // x = F(x, y switch { Span inner => inner }); + Diagnostic(ErrorCode.ERR_EscapeCall, "F(x, y switch { Span inner => inner })").WithArguments("Program.F(System.Span, System.Span)", "y").WithLocation(12, 13), + // (12,48): error CS8352: Cannot use variable 'inner' in this context because it may expose referenced variables outside of their declaration scope + // x = F(x, y switch { Span inner => inner }); + Diagnostic(ErrorCode.ERR_EscapeVariable, "inner").WithArguments("inner").WithLocation(12, 48)); + } + + [Fact] + public void SwitchExpression_Return() + { + var source = """ + using System; + class Program + { + static Span M() + { + Span outer = stackalloc int[100]; + return outer switch + { + Span inner => inner + }; + } + } + """; + var comp = CreateCompilationWithSpan(source); + comp.VerifyDiagnostics( + // (9,32): error CS8352: Cannot use variable 'inner' in this context because it may expose referenced variables outside of their declaration scope + // Span inner => inner + Diagnostic(ErrorCode.ERR_EscapeVariable, "inner").WithArguments("inner").WithLocation(9, 32)); + } + + [Fact] + public void SwitchExpression_YieldReturn() + { + var source = """ + using System; + using System.Collections.Generic; + class Program + { + static IEnumerable M() + { + Span outer = stackalloc int[100]; + yield return (outer switch + { + Span inner => inner + })[0]; + } + } + """; + var comp = CreateCompilationWithSpan(source); + comp.VerifyDiagnostics(); + } + + [Fact] + public void SwitchExpression_FieldInitializer() + { + var source = """ + using System; + class Program + { + static int F = (new Span() switch + { + Span inner => inner + })[0]; + } + """; + var comp = CreateCompilationWithSpan(source); + comp.VerifyDiagnostics(); + } + + [Fact] + public void UnsafeContext_LocalFunction_01() + { + var source = """ + #pragma warning disable 8321 + class Program + { + static ref int F0(ref int x, ref int y) + { + return ref x; + } + static void F1() + { + static ref int Local1(ref int x1, int y1) + { + return ref F0(ref x1, ref y1); + } + unsafe static ref int Local2(ref int x2, int y2) + { + return ref F0(ref x2, ref y2); + } + unsafe + { + static ref int Local3(ref int x3, int y3) + { + return ref F0(ref x3, ref y3); + } + unsafe static ref int Local4(ref int x4, int y4) + { + return ref F0(ref x4, ref y4); + } + } + } + } + """; + var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll); + comp.VerifyDiagnostics( + // (12,24): error CS8347: Cannot use a result of 'Program.F0(ref int, ref int)' in this context because it may expose variables referenced by parameter 'y' outside of their declaration scope + // return ref F0(ref x1, ref y1); + Diagnostic(ErrorCode.ERR_EscapeCall, "F0(ref x1, ref y1)").WithArguments("Program.F0(ref int, ref int)", "y").WithLocation(12, 24), + // (12,39): error CS8166: Cannot return a parameter by reference 'y1' because it is not a ref parameter + // return ref F0(ref x1, ref y1); + Diagnostic(ErrorCode.ERR_RefReturnParameter, "y1").WithArguments("y1").WithLocation(12, 39), + // (16,39): warning CS9087: This returns a parameter by reference 'y2' but it is not a ref parameter + // return ref F0(ref x2, ref y2); + Diagnostic(ErrorCode.WRN_RefReturnParameter, "y2").WithArguments("y2").WithLocation(16, 39), + // (22,43): warning CS9087: This returns a parameter by reference 'y3' but it is not a ref parameter + // return ref F0(ref x3, ref y3); + Diagnostic(ErrorCode.WRN_RefReturnParameter, "y3").WithArguments("y3").WithLocation(22, 43), + // (26,43): warning CS9087: This returns a parameter by reference 'y4' but it is not a ref parameter + // return ref F0(ref x4, ref y4); + Diagnostic(ErrorCode.WRN_RefReturnParameter, "y4").WithArguments("y4").WithLocation(26, 43)); + } + + [Fact] + public void UnsafeContext_LocalFunction_02() + { + var source = """ + #pragma warning disable 8321 + class A + { + internal static ref int F0(ref int x, ref int y) + { + return ref x; + } + } + class B1 : A + { + unsafe static void F1() + { + static ref int Local1(ref int x1, int y1) + { + return ref F0(ref x1, ref y1); + } + } + unsafe class B2 : A + { + static void F2() + { + static ref int Local2(ref int x2, int y2) + { + return ref F0(ref x2, ref y2); + } + } + } + """; + var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll); + comp.VerifyDiagnostics( + // (15,39): warning CS9087: This returns a parameter by reference 'y1' but it is not a ref parameter + // return ref F0(ref x1, ref y1); + Diagnostic(ErrorCode.WRN_RefReturnParameter, "y1").WithArguments("y1").WithLocation(15, 39), + // (24,39): warning CS9087: This returns a parameter by reference 'y2' but it is not a ref parameter + // return ref F0(ref x2, ref y2); + Diagnostic(ErrorCode.WRN_RefReturnParameter, "y2").WithArguments("y2").WithLocation(24, 39), + // (27,2): error CS1513: } expected + // } + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(27, 2)); + } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/StackAllocInitializerTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/StackAllocInitializerTests.cs index cb677d03b5b2f..73ca5a23f2b90 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/StackAllocInitializerTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/StackAllocInitializerTests.cs @@ -657,12 +657,21 @@ static void Method1(int[] array) // (7,37): error CS0306: The type 'Span' may not be used as a type argument // var q1 = from item in array select stackalloc int[3] { 1, 2, 3 }; Diagnostic(ErrorCode.ERR_BadTypeArgument, "select stackalloc int[3] { 1, 2, 3 }").WithArguments("System.Span").WithLocation(7, 37), + // (7,44): error CS8353: A result of a stackalloc expression of type 'Span' cannot be used in this context because it may be exposed outside of the containing method + // var q1 = from item in array select stackalloc int[3] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc int[3] { 1, 2, 3 }").WithArguments("System.Span").WithLocation(7, 44), // (8,37): error CS0306: The type 'Span' may not be used as a type argument // var q2 = from item in array select stackalloc int[ ] { 1, 2, 3 }; Diagnostic(ErrorCode.ERR_BadTypeArgument, "select stackalloc int[ ] { 1, 2, 3 }").WithArguments("System.Span").WithLocation(8, 37), + // (8,44): error CS8353: A result of a stackalloc expression of type 'Span' cannot be used in this context because it may be exposed outside of the containing method + // var q2 = from item in array select stackalloc int[ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc int[ ] { 1, 2, 3 }").WithArguments("System.Span").WithLocation(8, 44), // (9,37): error CS0306: The type 'Span' may not be used as a type argument // var q3 = from item in array select stackalloc [ ] { 1, 2, 3 }; - Diagnostic(ErrorCode.ERR_BadTypeArgument, "select stackalloc [ ] { 1, 2, 3 }").WithArguments("System.Span").WithLocation(9, 37) + Diagnostic(ErrorCode.ERR_BadTypeArgument, "select stackalloc [ ] { 1, 2, 3 }").WithArguments("System.Span").WithLocation(9, 37), + // (9,44): error CS8353: A result of a stackalloc expression of type 'Span' cannot be used in this context because it may be exposed outside of the containing method + // var q3 = from item in array select stackalloc [ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc [ ] { 1, 2, 3 }").WithArguments("System.Span").WithLocation(9, 44) ); } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/StructConstructorTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/StructConstructorTests.cs index 6fd294b8f8934..d972d3cffcbb7 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/StructConstructorTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/StructConstructorTests.cs @@ -3752,8 +3752,10 @@ public E2() { } Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "Field = stackalloc byte[512]").WithArguments("System.Span").WithLocation(9, 57)); } - [Fact] - public void FieldInitializer_EscapeAnalysis_04() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.Latest)] + public void FieldInitializer_EscapeAnalysis_04(LanguageVersion languageVersion) { var source = @"using System; @@ -3765,19 +3767,7 @@ ref struct Example public Example() {} static Span F(D d) => d(); }"; - var comp = CreateCompilationWithSpan(source, parseOptions: TestOptions.Regular10); - comp.VerifyDiagnostics( - // (5,31): error CS0188: The 'this' object cannot be used before all of its fields have been assigned. Consider updating to language version '11.0' to auto-default the unassigned fields. - // public Span Field = F(() => stackalloc byte[512]); - Diagnostic(ErrorCode.ERR_UseDefViolationThisUnsupportedVersion, "F").WithArguments("11.0").WithLocation(5, 31), - // (5,39): error CS8353: A result of a stackalloc expression of type 'Span' cannot be used in this context because it may be exposed outside of the containing method - // public Span Field = F(() => stackalloc byte[512]); - Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc byte[512]").WithArguments("System.Span").WithLocation(5, 39), - // (6,51): error CS8353: A result of a stackalloc expression of type 'Span' cannot be used in this context because it may be exposed outside of the containing method - // public Span Property { get; } = F(() => stackalloc byte[512]); - Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc byte[512]").WithArguments("System.Span").WithLocation(6, 51)); - - comp = CreateCompilationWithSpan(source); + var comp = CreateCompilationWithSpan(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); comp.VerifyDiagnostics( // (5,39): error CS8353: A result of a stackalloc expression of type 'Span' cannot be used in this context because it may be exposed outside of the containing method // public Span Field = F(() => stackalloc byte[512]); @@ -4101,6 +4091,71 @@ .maxstack 2 "); } + [Fact, WorkItem(66046, "https://github.com/dotnet/roslyn/issues/66046")] + public void ImplicitlyInitializedField_ConstructorInitializer_01() + { + var source = """ +public struct S1 +{ + public int F; + + S1(int x) {} + + public S1() : this(F) {} +} +"""; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (7,24): error CS0120: An object reference is required for the non-static field, method, or property 'S1.F' + // public S1() : this(F) {} + Diagnostic(ErrorCode.ERR_ObjectRequired, "F").WithArguments("S1.F").WithLocation(7, 24)); + } + + [Fact, WorkItem(66046, "https://github.com/dotnet/roslyn/issues/66046")] + public void ImplicitlyInitializedField_ConstructorInitializer_02() + { + var source = """ +public struct S1 +{ + public int F; + + S1(int x) {} + + public static int M(int y) => y; + + public S1() : this(M(F)) {} +} +"""; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (9,26): error CS0120: An object reference is required for the non-static field, method, or property 'S1.F' + // public S1() : this(M(F)) {} + Diagnostic(ErrorCode.ERR_ObjectRequired, "F").WithArguments("S1.F").WithLocation(9, 26)); + } + + [Fact, WorkItem(66046, "https://github.com/dotnet/roslyn/issues/66046")] + public void ImplicitlyInitializedField_ConstructorInitializer_03() + { + var source = """ +public struct S1 +{ + public int F; + + S1(int x) {} + + public S1() : base(F) {} +} +"""; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (7,12): error CS0522: 'S1': structs cannot call base class constructors + // public S1() : base(F) {} + Diagnostic(ErrorCode.ERR_StructWithBaseConstructorCall, "S1").WithArguments("S1").WithLocation(7, 12), + // (7,24): error CS0120: An object reference is required for the non-static field, method, or property 'S1.F' + // public S1() : base(F) {} + Diagnostic(ErrorCode.ERR_ObjectRequired, "F").WithArguments("S1.F").WithLocation(7, 24)); + } + [Theory] [InlineData(LanguageVersion.CSharp10)] [InlineData(LanguageVersion.CSharp11)] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UninitializedNonNullableFieldTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UninitializedNonNullableFieldTests.cs index 9fc5c93299504..d7c0dd21e88d2 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UninitializedNonNullableFieldTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UninitializedNonNullableFieldTests.cs @@ -2770,5 +2770,41 @@ public class C var actualAdditionalLocations = comp.GetDiagnostics().Single().AdditionalLocations; Assert.Equal(property.Locations.Single(), actualAdditionalLocations.Single()); } + + [Theory] + [CombinatorialData] + [WorkItem(66037, "https://github.com/dotnet/roslyn/issues/66037")] + public void TestAdditionalLocationOnCompilerDiagnostic(bool warnAsError) + { + var options = WithNullableEnable(); + if (warnAsError) + { + options = options.WithGeneralDiagnosticOption(ReportDiagnostic.Error); + } + + var comp = CreateCompilation(@" +public class B +{ + public B? f2; +} +public class C +{ + public B f; + static void Main() + { + new C() { f = { f2 = null }}; + } +}", options: options); + + var diagnostics = comp.GetDiagnostics(); + diagnostics.Verify( + // (8,14): warning CS8618: Non-nullable field 'f' must contain a non-null value when exiting constructor. Consider declaring the field as nullable. + // public B f; + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "f").WithArguments("field", "f").WithLocation(8, 14).WithWarningAsError(warnAsError)); + + var diagnostic = Assert.Single(diagnostics); + Assert.Single(diagnostic.AdditionalLocations); + } + } } diff --git a/src/Compilers/CSharp/Test/Symbol/Compilation/CompilationAPITests.cs b/src/Compilers/CSharp/Test/Symbol/Compilation/CompilationAPITests.cs index f1e52e10d3d9d..50b094d4b55dd 100644 --- a/src/Compilers/CSharp/Test/Symbol/Compilation/CompilationAPITests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Compilation/CompilationAPITests.cs @@ -3089,6 +3089,61 @@ static void M() { } Assert.Throws(() => genericMethod.Construct(typeArguments, default)); } + [Fact, WorkItem(65499, "https://github.com/dotnet/roslyn/issues/65499")] + public void NetModuleReference() + { + var module = CreateCompilation(string.Empty, options: TestOptions.ReleaseDll.WithOutputKind(OutputKind.NetModule)); + module.VerifyDiagnostics(); + + var moduleStream = new MemoryStream(); + var result = module.Emit(moduleStream); + Assert.True(result.Success); + moduleStream.Position = 0; + var moduleReference = MetadataReference.CreateFromStream(moduleStream, MetadataReferenceProperties.Module); + + var comp = CreateCompilation(string.Empty, references: new[] { moduleReference }); + comp.VerifyEmitDiagnostics(); + Assert.Equal(2, comp.Assembly.Modules.Length); + } + + [Fact, WorkItem(65499, "https://github.com/dotnet/roslyn/issues/65499")] + public void NetModuleReference_AssemblySpecifiedAsModule() + { + var module = CreateCompilation(string.Empty); + module.VerifyDiagnostics(); + + var moduleStream = new MemoryStream(); + var result = module.Emit(moduleStream); + Assert.True(result.Success); + moduleStream.Position = 0; + var moduleReference = MetadataReference.CreateFromStream(moduleStream, MetadataReferenceProperties.Module); + + var comp = CreateCompilation(string.Empty, references: new[] { moduleReference }); + comp.VerifyEmitDiagnostics( + // error CS1542: '' cannot be added to this assembly because it already is an assembly + Diagnostic(ErrorCode.ERR_AddModuleAssembly).WithArguments("").WithLocation(1, 1)); + Assert.Equal(1, comp.Assembly.Modules.Length); + } + + [Fact, WorkItem(65499, "https://github.com/dotnet/roslyn/issues/65499")] + public void NetModuleReference_ModuleSpecifiedAsAssembly() + { + var module = CreateCompilation(string.Empty, options: TestOptions.ReleaseDll.WithOutputKind(OutputKind.NetModule)); + module.VerifyDiagnostics(); + + var moduleStream = new MemoryStream(); + var result = module.Emit(moduleStream); + Assert.True(result.Success); + moduleStream.Position = 0; + var moduleReference = MetadataReference.CreateFromStream(moduleStream, MetadataReferenceProperties.Assembly); + + var comp = CreateCompilation(string.Empty, references: new[] { moduleReference }); + comp.VerifyEmitDiagnostics( + // error CS1509: The referenced file '' is not an assembly + Diagnostic(ErrorCode.ERR_ImportNonAssembly).WithArguments("").WithLocation(1, 1)); + Assert.Equal(1, comp.Assembly.Modules.Length); + } + #region Script return values [ConditionalFact(typeof(DesktopOnly))] diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/GenericConstraintTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/GenericConstraintTests.cs index 9adb4625f58a2..6abdb823d032f 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/GenericConstraintTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/GenericConstraintTests.cs @@ -1480,63 +1480,61 @@ static void Main() compilation.VerifyIL("C.M(T1, T2, U1, U2)", @" { - // Code size 193 (0xc1) + // Code size 195 (0xc3) .maxstack 2 .locals init (T1 V_0, - U1 V_1) + U1 V_1) IL_0000: ldarga.s V_0 - IL_0002: ldloca.s V_0 - IL_0004: initobj ""T1"" - IL_000a: ldloc.0 - IL_000b: box ""T1"" - IL_0010: brtrue.s IL_001a - IL_0012: ldobj ""T1"" - IL_0017: stloc.0 - IL_0018: ldloca.s V_0 - IL_001a: ldarga.s V_0 - IL_001c: constrained. ""T1"" - IL_0022: callvirt ""object I.P.get"" - IL_0027: constrained. ""T1"" - IL_002d: callvirt ""void I.P.set"" - IL_0032: ldarga.s V_0 - IL_0034: constrained. ""T1"" - IL_003a: callvirt ""void I.M()"" - IL_003f: ldarg.1 - IL_0040: box ""T2"" - IL_0045: ldarg.1 - IL_0046: box ""T2"" - IL_004b: callvirt ""object A.P.get"" - IL_0050: callvirt ""void A.P.set"" - IL_0055: ldarg.1 - IL_0056: box ""T2"" - IL_005b: callvirt ""void A.M()"" - IL_0060: ldarga.s V_2 - IL_0062: ldloca.s V_1 - IL_0064: initobj ""U1"" - IL_006a: ldloc.1 - IL_006b: box ""U1"" - IL_0070: brtrue.s IL_007a - IL_0072: ldobj ""U1"" - IL_0077: stloc.1 - IL_0078: ldloca.s V_1 - IL_007a: ldarga.s V_2 - IL_007c: constrained. ""U1"" - IL_0082: callvirt ""object I.P.get"" - IL_0087: constrained. ""U1"" - IL_008d: callvirt ""void I.P.set"" - IL_0092: ldarga.s V_2 - IL_0094: constrained. ""U1"" - IL_009a: callvirt ""void I.M()"" - IL_009f: ldarg.3 - IL_00a0: box ""U2"" - IL_00a5: ldarg.3 - IL_00a6: box ""U2"" - IL_00ab: callvirt ""object A.P.get"" - IL_00b0: callvirt ""void A.P.set"" - IL_00b5: ldarg.3 - IL_00b6: box ""U2"" - IL_00bb: callvirt ""void A.M()"" - IL_00c0: ret + IL_0002: ldtoken ""T1"" + IL_0007: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000c: call ""bool System.Type.IsValueType.get"" + IL_0011: brtrue.s IL_001b + IL_0013: ldobj ""T1"" + IL_0018: stloc.0 + IL_0019: ldloca.s V_0 + IL_001b: ldarga.s V_0 + IL_001d: constrained. ""T1"" + IL_0023: callvirt ""object I.P.get"" + IL_0028: constrained. ""T1"" + IL_002e: callvirt ""void I.P.set"" + IL_0033: ldarga.s V_0 + IL_0035: constrained. ""T1"" + IL_003b: callvirt ""void I.M()"" + IL_0040: ldarg.1 + IL_0041: box ""T2"" + IL_0046: ldarg.1 + IL_0047: box ""T2"" + IL_004c: callvirt ""object A.P.get"" + IL_0051: callvirt ""void A.P.set"" + IL_0056: ldarg.1 + IL_0057: box ""T2"" + IL_005c: callvirt ""void A.M()"" + IL_0061: ldarga.s V_2 + IL_0063: ldtoken ""U1"" + IL_0068: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_006d: call ""bool System.Type.IsValueType.get"" + IL_0072: brtrue.s IL_007c + IL_0074: ldobj ""U1"" + IL_0079: stloc.1 + IL_007a: ldloca.s V_1 + IL_007c: ldarga.s V_2 + IL_007e: constrained. ""U1"" + IL_0084: callvirt ""object I.P.get"" + IL_0089: constrained. ""U1"" + IL_008f: callvirt ""void I.P.set"" + IL_0094: ldarga.s V_2 + IL_0096: constrained. ""U1"" + IL_009c: callvirt ""void I.M()"" + IL_00a1: ldarg.3 + IL_00a2: box ""U2"" + IL_00a7: ldarg.3 + IL_00a8: box ""U2"" + IL_00ad: callvirt ""object A.P.get"" + IL_00b2: callvirt ""void A.P.set"" + IL_00b7: ldarg.3 + IL_00b8: box ""U2"" + IL_00bd: callvirt ""void A.M()"" + IL_00c2: ret }"); } @@ -1589,28 +1587,27 @@ static void Main() compilation.VerifyIL("C.M(T, U)", @" { - // Code size 61 (0x3d) + // Code size 62 (0x3e) .maxstack 4 .locals init (T V_0) IL_0000: ldarga.s V_0 - IL_0002: ldloca.s V_0 - IL_0004: initobj ""T"" - IL_000a: ldloc.0 - IL_000b: box ""T"" - IL_0010: brtrue.s IL_001a - IL_0012: ldobj ""T"" - IL_0017: stloc.0 - IL_0018: ldloca.s V_0 - IL_001a: ldc.i4.0 - IL_001b: box ""int"" - IL_0020: ldarg.1 - IL_0021: box ""U"" - IL_0026: ldc.i4.1 - IL_0027: box ""int"" - IL_002c: callvirt ""object A.this[object].get"" - IL_0031: constrained. ""T"" - IL_0037: callvirt ""void I.this[object].set"" - IL_003c: ret + IL_0002: ldtoken ""T"" + IL_0007: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000c: call ""bool System.Type.IsValueType.get"" + IL_0011: brtrue.s IL_001b + IL_0013: ldobj ""T"" + IL_0018: stloc.0 + IL_0019: ldloca.s V_0 + IL_001b: ldc.i4.0 + IL_001c: box ""int"" + IL_0021: ldarg.1 + IL_0022: box ""U"" + IL_0027: ldc.i4.1 + IL_0028: box ""int"" + IL_002d: callvirt ""object A.this[object].get"" + IL_0032: constrained. ""T"" + IL_0038: callvirt ""void I.this[object].set"" + IL_003d: ret }"); } @@ -4544,11 +4541,11 @@ static void Main() compilation.VerifyIL("B.M1(T)", @" { - // Code size 216 (0xd8) + // Code size 218 (0xda) .maxstack 4 .locals init (int V_0, - T& V_1, - T V_2) + T& V_1, + T V_2) IL_0000: ldarga.s V_0 IL_0002: dup IL_0003: constrained. ""T"" @@ -4574,53 +4571,51 @@ .locals init (int V_0, IL_003c: ldarga.s V_0 IL_003e: stloc.1 IL_003f: ldloc.1 - IL_0040: ldloca.s V_2 - IL_0042: initobj ""T"" - IL_0048: ldloc.2 - IL_0049: box ""T"" - IL_004e: brtrue.s IL_0058 - IL_0050: ldobj ""T"" - IL_0055: stloc.2 - IL_0056: ldloca.s V_2 - IL_0058: ldloc.1 - IL_0059: constrained. ""T"" - IL_005f: callvirt ""int I.P.get"" - IL_0064: ldc.i4.2 - IL_0065: add - IL_0066: constrained. ""T"" - IL_006c: callvirt ""void I.P.set"" - IL_0071: ldarga.s V_0 - IL_0073: stloc.1 - IL_0074: ldloc.1 - IL_0075: ldloca.s V_2 - IL_0077: initobj ""T"" - IL_007d: ldloc.2 - IL_007e: box ""T"" - IL_0083: brtrue.s IL_008d - IL_0085: ldobj ""T"" - IL_008a: stloc.2 - IL_008b: ldloca.s V_2 - IL_008d: ldc.i4.0 - IL_008e: ldloc.1 + IL_0040: ldtoken ""T"" + IL_0045: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_004a: call ""bool System.Type.IsValueType.get"" + IL_004f: brtrue.s IL_0059 + IL_0051: ldobj ""T"" + IL_0056: stloc.2 + IL_0057: ldloca.s V_2 + IL_0059: ldloc.1 + IL_005a: constrained. ""T"" + IL_0060: callvirt ""int I.P.get"" + IL_0065: ldc.i4.2 + IL_0066: add + IL_0067: constrained. ""T"" + IL_006d: callvirt ""void I.P.set"" + IL_0072: ldarga.s V_0 + IL_0074: stloc.1 + IL_0075: ldloc.1 + IL_0076: ldtoken ""T"" + IL_007b: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0080: call ""bool System.Type.IsValueType.get"" + IL_0085: brtrue.s IL_008f + IL_0087: ldobj ""T"" + IL_008c: stloc.2 + IL_008d: ldloca.s V_2 IL_008f: ldc.i4.0 - IL_0090: constrained. ""T"" - IL_0096: callvirt ""int I.this[int].get"" - IL_009b: ldc.i4.2 - IL_009c: add - IL_009d: constrained. ""T"" - IL_00a3: callvirt ""void I.this[int].set"" - IL_00a8: ldstr ""{0}, {1}"" - IL_00ad: ldarga.s V_0 - IL_00af: constrained. ""T"" - IL_00b5: callvirt ""int I.P.get"" - IL_00ba: box ""int"" - IL_00bf: ldarga.s V_0 - IL_00c1: ldc.i4.0 - IL_00c2: constrained. ""T"" - IL_00c8: callvirt ""int I.this[int].get"" - IL_00cd: box ""int"" - IL_00d2: call ""void System.Console.WriteLine(string, object, object)"" - IL_00d7: ret + IL_0090: ldloc.1 + IL_0091: ldc.i4.0 + IL_0092: constrained. ""T"" + IL_0098: callvirt ""int I.this[int].get"" + IL_009d: ldc.i4.2 + IL_009e: add + IL_009f: constrained. ""T"" + IL_00a5: callvirt ""void I.this[int].set"" + IL_00aa: ldstr ""{0}, {1}"" + IL_00af: ldarga.s V_0 + IL_00b1: constrained. ""T"" + IL_00b7: callvirt ""int I.P.get"" + IL_00bc: box ""int"" + IL_00c1: ldarga.s V_0 + IL_00c3: ldc.i4.0 + IL_00c4: constrained. ""T"" + IL_00ca: callvirt ""int I.this[int].get"" + IL_00cf: box ""int"" + IL_00d4: call ""void System.Console.WriteLine(string, object, object)"" + IL_00d9: ret } "); compilation.VerifyIL("B.M2(T)", diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/LocalFunctionTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/LocalFunctionTests.cs index d00b5f4beaefd..0d5d2a56ac694 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/LocalFunctionTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/LocalFunctionTests.cs @@ -189,5 +189,239 @@ partial void local() { } // } Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(7, 1)); } + + [Fact, WorkItem(65938, "https://github.com/dotnet/roslyn/issues/65938")] + public void StaticLocalFunction_CapturingMethodGroup() + { + CreateCompilation(""" + using System; + + var c = new C(); + LocalFunc(); + NonStatic(); + + static void LocalFunc() + { + var x1 = c.MyExtension; + var y1 = new Func(c.MyExtension); + } + + void NonStatic() + { + Action f = static () => + { + var x2 = c.MyExtension; + var y2 = new Func(c.MyExtension); + }; + } + + public class C + { + } + + public static class Extensions + { + public static string MyExtension(this C c) + => string.Empty; + } + """).VerifyDiagnostics( + // (9,14): error CS8421: A static local function cannot contain a reference to 'c'. + // var x1 = c.MyExtension; + Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureVariable, "c").WithArguments("c").WithLocation(9, 14), + // (10,31): error CS8421: A static local function cannot contain a reference to 'c'. + // var y1 = new Func(c.MyExtension); + Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureVariable, "c").WithArguments("c").WithLocation(10, 31), + // (17,18): error CS8820: A static anonymous function cannot contain a reference to 'c'. + // var x2 = c.MyExtension; + Diagnostic(ErrorCode.ERR_StaticAnonymousFunctionCannotCaptureVariable, "c").WithArguments("c").WithLocation(17, 18), + // (18,35): error CS8820: A static anonymous function cannot contain a reference to 'c'. + // var y2 = new Func(c.MyExtension); + Diagnostic(ErrorCode.ERR_StaticAnonymousFunctionCannotCaptureVariable, "c").WithArguments("c").WithLocation(18, 35)); + } + + [Fact] + public void StaticLocalFunction_CapturingMethodGroup2() + { + CreateCompilation(""" + using System; + + var c = new C(); + LocalFunc(); + NonStatic(); + + static void LocalFunc() + { + var x1 = Extensions.MyExtension; + var y1 = new Func(Extensions.MyExtension); + } + + void NonStatic() + { + Action f = static () => + { + var x2 = Extensions.MyExtension; + var y2 = new Func(Extensions.MyExtension); + }; + } + + public class C + { + } + + public static class Extensions + { + public static string MyExtension(this C c) + => string.Empty; + } + """).VerifyEmitDiagnostics(); + } + + [Fact] + public void StaticLocalFunction_CapturingMethodGroup3() + { + CreateCompilation(""" + using System; + public class Base { } + + public class C : Base + { + public void M() + { + LocalFunc(); + + static void LocalFunc() + { + var x1 = this.MyExtension; + var x2 = new Func(this.MyExtension); + var y1 = base.MyExtension; + var y2 = new Func(base.MyExtension); + } + } + } + + internal static class Extensions + { + public static string MyExtension(this Base c) + => string.Empty; + } + """).VerifyDiagnostics( + // (12,22): error CS8422: A static local function cannot contain a reference to 'this' or 'base'. + // var x1 = this.MyExtension; + Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureThis, "this").WithLocation(12, 22), + // (13,39): error CS8422: A static local function cannot contain a reference to 'this' or 'base'. + // var x2 = new Func(this.MyExtension); + Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureThis, "this").WithLocation(13, 39), + // (14,22): error CS8422: A static local function cannot contain a reference to 'this' or 'base'. + // var y1 = base.MyExtension; + Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureThis, "base").WithLocation(14, 22), + // (14,27): error CS0117: 'Base' does not contain a definition for 'MyExtension' + // var y1 = base.MyExtension; + Diagnostic(ErrorCode.ERR_NoSuchMember, "MyExtension").WithArguments("Base", "MyExtension").WithLocation(14, 27), + // (15,39): error CS8422: A static local function cannot contain a reference to 'this' or 'base'. + // var y2 = new Func(base.MyExtension); + Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureThis, "base").WithLocation(15, 39), + // (15,44): error CS0117: 'Base' does not contain a definition for 'MyExtension' + // var y2 = new Func(base.MyExtension); + Diagnostic(ErrorCode.ERR_NoSuchMember, "MyExtension").WithArguments("Base", "MyExtension").WithLocation(15, 44)); + } + + [Fact] + public void StaticLocalFunction_CapturingMethodGroup4() + { + CreateCompilation(""" + using System; + public class Base { } + + public class C : Base + { + public void M() + { + NonStatic(); + + void NonStatic() + { + Action f = static () => + { + var x1 = this.MyExtension; + var x2 = new Func(this.MyExtension); + }; + } + } + } + + internal static class Extensions + { + public static string MyExtension(this Base c) + => string.Empty; + } + """).VerifyDiagnostics( + // (14,26): error CS8821: A static anonymous function cannot contain a reference to 'this' or 'base'. + // var x1 = this.MyExtension; + Diagnostic(ErrorCode.ERR_StaticAnonymousFunctionCannotCaptureThis, "this").WithLocation(14, 26), + // (15,43): error CS8821: A static anonymous function cannot contain a reference to 'this' or 'base'. + // var x2 = new Func(this.MyExtension); + Diagnostic(ErrorCode.ERR_StaticAnonymousFunctionCannotCaptureThis, "this").WithLocation(15, 43)); + } + + [Fact] + public void StaticLocalFunction_CapturingMethodGroup5() + { + CreateCompilation(""" + using System; + public class Base { } + + public class C : Base + { + public void M() + { + NonStatic(); + + void NonStatic() + { + Action f = static () => + { + var x1 = base.MyExtension; + var x2 = new Func(base.MyExtension); + }; + } + } + } + + internal static class Extensions + { + public static string MyExtension(this Base c) + => string.Empty; + } + """).VerifyDiagnostics( + // (14,31): error CS0117: 'Base' does not contain a definition for 'MyExtension' + // var x1 = base.MyExtension; + Diagnostic(ErrorCode.ERR_NoSuchMember, "MyExtension").WithArguments("Base", "MyExtension").WithLocation(14, 31), + // (15,48): error CS0117: 'Base' does not contain a definition for 'MyExtension' + // var x2 = new Func(base.MyExtension); + Diagnostic(ErrorCode.ERR_NoSuchMember, "MyExtension").WithArguments("Base", "MyExtension").WithLocation(15, 48)); + } + + [Fact] + public void StaticLocalFunction_CapturingMethodGroup6() + { + CreateCompilation(""" + using System; + + static class Extensions + { + static void F() + { + LocalFunc(); + static void LocalFunc() + { + var x = MyExtension; + var y = new Func(MyExtension); + } + } + static string MyExtension(this object o) + => string.Empty; + } + """).VerifyEmitDiagnostics(); + } } } diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/LocalFunctionParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/LocalFunctionParsingTests.cs index cad2b13d8f5af..b658ff625abbd 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/LocalFunctionParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/LocalFunctionParsingTests.cs @@ -4,11 +4,11 @@ #nullable disable +using System.Linq; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; -using System.Linq; using Xunit; using Xunit.Abstractions; @@ -2110,6 +2110,356 @@ void checkNodes() } } + [Fact, WorkItem(32106, "https://github.com/dotnet/roslyn/issues/32106")] + public void DuplicateAsyncs1() + { + const string text = """ + class Program + { + void M() + { + #pragma warning disable 1998, 8321 + async async void F() { } + } + } + """; + + CreateCompilation(text).VerifyDiagnostics( + // (6,15): error CS1031: Type expected + // async async void F() { } + Diagnostic(ErrorCode.ERR_TypeExpected, "async").WithLocation(6, 15), + // (6,15): error CS1004: Duplicate 'async' modifier + // async async void F() { } + Diagnostic(ErrorCode.ERR_DuplicateModifier, "async").WithArguments("async").WithLocation(6, 15)); + + UsingDeclaration(text, options: TestOptions.Regular9, + // (6,15): error CS1031: Type expected + // async async void F() { } + Diagnostic(ErrorCode.ERR_TypeExpected, "async").WithLocation(6, 15)); + checkNodes(); + + void checkNodes() + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "Program"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + N(SyntaxKind.VoidKeyword); + { + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.LocalFunctionStatement); + { + N(SyntaxKind.AsyncKeyword); + N(SyntaxKind.AsyncKeyword); + N(SyntaxKind.PredefinedType); + N(SyntaxKind.VoidKeyword); + N(SyntaxKind.IdentifierToken, "F"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + } + } + N(SyntaxKind.CloseBraceToken); + } + EOF(); + } + } + + [Fact, WorkItem(32106, "https://github.com/dotnet/roslyn/issues/32106")] + public void DuplicateAsyncs2() + { + const string text = """ + class Program + { + void M() + { + #pragma warning disable 1998, 8321 + async async async void F() { } + } + } + """; + + CreateCompilation(text).VerifyDiagnostics( + // (6,15): error CS1031: Type expected + // async async async void F() { } + Diagnostic(ErrorCode.ERR_TypeExpected, "async").WithLocation(6, 15), + // (6,15): error CS1004: Duplicate 'async' modifier + // async async async void F() { } + Diagnostic(ErrorCode.ERR_DuplicateModifier, "async").WithArguments("async").WithLocation(6, 15), + // (6,21): error CS1031: Type expected + // async async async void F() { } + Diagnostic(ErrorCode.ERR_TypeExpected, "async").WithLocation(6, 21)); + + UsingDeclaration(text, options: TestOptions.Regular9, + // (6,15): error CS1031: Type expected + // async async async void F() { } + Diagnostic(ErrorCode.ERR_TypeExpected, "async").WithLocation(6, 15), + // (6,21): error CS1031: Type expected + // async async async void F() { } + Diagnostic(ErrorCode.ERR_TypeExpected, "async").WithLocation(6, 21)); + checkNodes(); + + void checkNodes() + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "Program"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + N(SyntaxKind.VoidKeyword); + { + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.LocalFunctionStatement); + { + N(SyntaxKind.AsyncKeyword); + N(SyntaxKind.AsyncKeyword); + N(SyntaxKind.AsyncKeyword); + N(SyntaxKind.PredefinedType); + N(SyntaxKind.VoidKeyword); + N(SyntaxKind.IdentifierToken, "F"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + } + } + N(SyntaxKind.CloseBraceToken); + } + EOF(); + } + } + + [Fact, WorkItem(32106, "https://github.com/dotnet/roslyn/issues/32106")] + public void DuplicateAsyncs3() + { + const string text = """ + class Program + { + void M() + { + #pragma warning disable 1998, 8321 + async async async async void F() { } + } + } + """; + + CreateCompilation(text).VerifyDiagnostics( + // (6,15): error CS1031: Type expected + // async async async async void F() { } + Diagnostic(ErrorCode.ERR_TypeExpected, "async").WithLocation(6, 15), + // (6,15): error CS1004: Duplicate 'async' modifier + // async async async async void F() { } + Diagnostic(ErrorCode.ERR_DuplicateModifier, "async").WithArguments("async").WithLocation(6, 15), + // (6,21): error CS1031: Type expected + // async async async async void F() { } + Diagnostic(ErrorCode.ERR_TypeExpected, "async").WithLocation(6, 21), + // (6,27): error CS1031: Type expected + // async async async async void F() { } + Diagnostic(ErrorCode.ERR_TypeExpected, "async").WithLocation(6, 27)); + + UsingDeclaration(text, options: TestOptions.Regular9, + // (6,15): error CS1031: Type expected + // async async async async void F() { } + Diagnostic(ErrorCode.ERR_TypeExpected, "async").WithLocation(6, 15), + // (6,21): error CS1031: Type expected + // async async async async void F() { } + Diagnostic(ErrorCode.ERR_TypeExpected, "async").WithLocation(6, 21), + // (6,27): error CS1031: Type expected + // async async async async void F() { } + Diagnostic(ErrorCode.ERR_TypeExpected, "async").WithLocation(6, 27)); + checkNodes(); + + void checkNodes() + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "Program"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + N(SyntaxKind.VoidKeyword); + { + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.LocalFunctionStatement); + { + N(SyntaxKind.AsyncKeyword); + N(SyntaxKind.AsyncKeyword); + N(SyntaxKind.AsyncKeyword); + N(SyntaxKind.AsyncKeyword); + N(SyntaxKind.PredefinedType); + N(SyntaxKind.VoidKeyword); + N(SyntaxKind.IdentifierToken, "F"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + } + } + N(SyntaxKind.CloseBraceToken); + } + EOF(); + } + } + + [Fact, WorkItem(32106, "https://github.com/dotnet/roslyn/issues/32106")] + public void DuplicateAsyncs4() + { + const string text = """ + class Program + { + void M() + { + #pragma warning disable 1998, 8321 + async async async async async void F() { } + } + } + """; + + CreateCompilation(text).VerifyDiagnostics( + // (6,15): error CS1031: Type expected + // async async async async async void F() { } + Diagnostic(ErrorCode.ERR_TypeExpected, "async").WithLocation(6, 15), + // (6,15): error CS1004: Duplicate 'async' modifier + // async async async async async void F() { } + Diagnostic(ErrorCode.ERR_DuplicateModifier, "async").WithArguments("async").WithLocation(6, 15), + // (6,21): error CS1031: Type expected + // async async async async async void F() { } + Diagnostic(ErrorCode.ERR_TypeExpected, "async").WithLocation(6, 21), + // (6,27): error CS1031: Type expected + // async async async async async void F() { } + Diagnostic(ErrorCode.ERR_TypeExpected, "async").WithLocation(6, 27), + // (6,33): error CS1031: Type expected + // async async async async async void F() { } + Diagnostic(ErrorCode.ERR_TypeExpected, "async").WithLocation(6, 33)); + + UsingDeclaration(text, options: TestOptions.Regular9, + // (6,15): error CS1031: Type expected + // async async async async async void F() { } + Diagnostic(ErrorCode.ERR_TypeExpected, "async").WithLocation(6, 15), + // (6,21): error CS1031: Type expected + // async async async async async void F() { } + Diagnostic(ErrorCode.ERR_TypeExpected, "async").WithLocation(6, 21), + // (6,27): error CS1031: Type expected + // async async async async async void F() { } + Diagnostic(ErrorCode.ERR_TypeExpected, "async").WithLocation(6, 27), + // (6,33): error CS1031: Type expected + // async async async async async void F() { } + Diagnostic(ErrorCode.ERR_TypeExpected, "async").WithLocation(6, 33)); + checkNodes(); + + void checkNodes() + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "Program"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + N(SyntaxKind.VoidKeyword); + { + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.LocalFunctionStatement); + { + N(SyntaxKind.AsyncKeyword); + N(SyntaxKind.AsyncKeyword); + N(SyntaxKind.AsyncKeyword); + N(SyntaxKind.AsyncKeyword); + N(SyntaxKind.AsyncKeyword); + N(SyntaxKind.PredefinedType); + N(SyntaxKind.VoidKeyword); + N(SyntaxKind.IdentifierToken, "F"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + } + } + N(SyntaxKind.CloseBraceToken); + } + EOF(); + } + } + [Fact] public void ReturnTypeBeforeStatic() { diff --git a/src/Compilers/Core/CodeAnalysisTest/MetadataReferences/MetadataReferenceTests.cs b/src/Compilers/Core/CodeAnalysisTest/MetadataReferences/MetadataReferenceTests.cs index 4b7d1c3adb421..a3e508c9c85c4 100644 --- a/src/Compilers/Core/CodeAnalysisTest/MetadataReferences/MetadataReferenceTests.cs +++ b/src/Compilers/Core/CodeAnalysisTest/MetadataReferences/MetadataReferenceTests.cs @@ -56,11 +56,16 @@ public void CreateFrom_Errors() } #endif - [Fact] - public void CreateFromImage() + [Theory, CombinatorialData] + public void CreateFromImage_Assembly(bool module, bool immutableArray, bool explicitProperties) { - var r = MetadataReference.CreateFromImage(ResourcesNet451.mscorlib); + var peImage = module ? TestResources.MetadataTests.NetModule01.ModuleCS00 : ResourcesNet451.mscorlib; + var properties = explicitProperties ? MetadataReferenceProperties.Assembly : default; + var r = immutableArray + ? MetadataReference.CreateFromImage(peImage.AsImmutable(), properties) + : MetadataReference.CreateFromImage(peImage.AsEnumerable(), properties); + Assert.IsAssignableFrom(r.GetMetadata()); Assert.Null(r.FilePath); Assert.Equal(CodeAnalysisResources.InMemoryAssembly, r.Display); Assert.Equal(MetadataImageKind.Assembly, r.Properties.Kind); @@ -68,6 +73,22 @@ public void CreateFromImage() Assert.True(r.Properties.Aliases.IsEmpty); } + [Theory, CombinatorialData] + public void CreateFromImage_Module(bool module, bool immutableArray) + { + var peImage = module ? TestResources.MetadataTests.NetModule01.ModuleCS00 : ResourcesNet451.mscorlib; + var r = immutableArray + ? MetadataReference.CreateFromImage(peImage.AsImmutable(), MetadataReferenceProperties.Module) + : MetadataReference.CreateFromImage(peImage.AsEnumerable(), MetadataReferenceProperties.Module); + + Assert.IsAssignableFrom(r.GetMetadata()); + Assert.Null(r.FilePath); + Assert.Equal(CodeAnalysisResources.InMemoryModule, r.Display); + Assert.Equal(MetadataImageKind.Module, r.Properties.Kind); + Assert.False(r.Properties.EmbedInteropTypes); + Assert.True(r.Properties.Aliases.IsEmpty); + } + [Fact] public void CreateFromStream_FileStream() { @@ -101,12 +122,47 @@ public void CreateFromStream_MemoryStream() ((AssemblyMetadata)r.GetMetadataNoCopy()).GetAssembly().Identity.GetDisplayName()); } - [Fact] - public void CreateFromFile_Assembly() + [Theory, CombinatorialData] + public void CreateFromStream_Assembly(bool module, bool explicitProperties) { - var file = Temp.CreateFile().WriteAllBytes(ResourcesNet451.mscorlib); + var peImage = module ? TestResources.MetadataTests.NetModule01.ModuleCS00 : ResourcesNet451.mscorlib; + var r = MetadataReference.CreateFromStream( + new MemoryStream(peImage, writable: false), + explicitProperties ? MetadataReferenceProperties.Assembly : default); + + Assert.IsAssignableFrom(r.GetMetadata()); + Assert.Null(r.FilePath); + Assert.Equal(CodeAnalysisResources.InMemoryAssembly, r.Display); + Assert.Equal(MetadataImageKind.Assembly, r.Properties.Kind); + Assert.False(r.Properties.EmbedInteropTypes); + Assert.True(r.Properties.Aliases.IsEmpty); + } + + [Theory, CombinatorialData] + public void CreateFromStream_Module(bool module) + { + var peImage = module ? TestResources.MetadataTests.NetModule01.ModuleCS00 : ResourcesNet451.mscorlib; + var r = MetadataReference.CreateFromStream( + new MemoryStream(peImage, writable: false), + MetadataReferenceProperties.Module); + + Assert.IsAssignableFrom(r.GetMetadata()); + Assert.Null(r.FilePath); + Assert.Equal(CodeAnalysisResources.InMemoryModule, r.Display); + Assert.Equal(MetadataImageKind.Module, r.Properties.Kind); + Assert.False(r.Properties.EmbedInteropTypes); + Assert.True(r.Properties.Aliases.IsEmpty); + } - var r = MetadataReference.CreateFromFile(file.Path); + [Theory, CombinatorialData] + public void CreateFromFile_Assembly(bool module, bool explicitProperties) + { + var peImage = module ? TestResources.MetadataTests.NetModule01.ModuleCS00 : ResourcesNet451.mscorlib; + var file = Temp.CreateFile().WriteAllBytes(peImage); + + var r = MetadataReference.CreateFromFile(file.Path, + explicitProperties ? MetadataReferenceProperties.Assembly : default); + Assert.IsAssignableFrom(r.GetMetadata()); Assert.Equal(file.Path, r.FilePath); Assert.Equal(file.Path, r.Display); Assert.Equal(MetadataImageKind.Assembly, r.Properties.Kind); @@ -119,15 +175,17 @@ public void CreateFromFile_Assembly() // check that the metadata is in memory and the file can be deleted: File.Delete(file.Path); var metadata = (AssemblyMetadata)r.GetMetadataNoCopy(); - Assert.Equal("CommonLanguageRuntimeLibrary", metadata.GetModules()[0].Name); + Assert.Equal(module ? "ModuleCS00.netmodule" : "CommonLanguageRuntimeLibrary", metadata.GetModules()[0].Name); } - [Fact] - public void CreateFromFile_Module() + [Theory, CombinatorialData] + public void CreateFromFile_Module(bool module) { - var file = Temp.CreateFile().WriteAllBytes(TestResources.MetadataTests.NetModule01.ModuleCS00); + var peImage = module ? TestResources.MetadataTests.NetModule01.ModuleCS00 : ResourcesNet451.mscorlib; + var file = Temp.CreateFile().WriteAllBytes(peImage); var r = MetadataReference.CreateFromFile(file.Path, MetadataReferenceProperties.Module); + Assert.IsAssignableFrom(r.GetMetadata()); Assert.Equal(file.Path, r.FilePath); Assert.Equal(file.Path, r.Display); Assert.Equal(MetadataImageKind.Module, r.Properties.Kind); @@ -140,7 +198,7 @@ public void CreateFromFile_Module() // check that the metadata is in memory and the file can be deleted: File.Delete(file.Path); var metadata = (ModuleMetadata)r.GetMetadataNoCopy(); - Assert.Equal("ModuleCS00.netmodule", metadata.Name); + Assert.Equal(module ? "ModuleCS00.netmodule" : "CommonLanguageRuntimeLibrary", metadata.Name); } [Fact] diff --git a/src/Compilers/Core/MSBuildTask/Microsoft.Build.Tasks.CodeAnalysis.csproj b/src/Compilers/Core/MSBuildTask/Microsoft.Build.Tasks.CodeAnalysis.csproj index 9f2d181d8eade..adda86fdd469e 100644 --- a/src/Compilers/Core/MSBuildTask/Microsoft.Build.Tasks.CodeAnalysis.csproj +++ b/src/Compilers/Core/MSBuildTask/Microsoft.Build.Tasks.CodeAnalysis.csproj @@ -66,9 +66,8 @@ - - - + + diff --git a/src/Compilers/Core/MSBuildTask/Microsoft.Managed.Core.targets b/src/Compilers/Core/MSBuildTask/Microsoft.Managed.Core.targets index 5dea5a15e6e6a..4436b3841f61d 100644 --- a/src/Compilers/Core/MSBuildTask/Microsoft.Managed.Core.targets +++ b/src/Compilers/Core/MSBuildTask/Microsoft.Managed.Core.targets @@ -92,6 +92,7 @@ <_ImplicitlySkipAnalyzers>true <_SkipAnalyzers>true @@ -350,4 +351,4 @@ - \ No newline at end of file + diff --git a/src/Compilers/Core/MSBuildTaskTests/TargetTests.cs b/src/Compilers/Core/MSBuildTaskTests/TargetTests.cs index b2335b269d65f..62aa4d52b4f87 100644 --- a/src/Compilers/Core/MSBuildTaskTests/TargetTests.cs +++ b/src/Compilers/Core/MSBuildTaskTests/TargetTests.cs @@ -755,6 +755,7 @@ public void TestImplicitlySkipAnalyzers( var expectedImplicitlySkippedAnalyzers = analyzersEnabled && implicitBuild == true && sdkStyleProject == true && + optimizeImplicitBuild != false && (treatWarningsAsErrors != true || optimizeImplicitBuild == true); var expectedImplicitlySkippedAnalyzersValue = expectedImplicitlySkippedAnalyzers ? "true" : ""; var actualImplicitlySkippedAnalyzersValue = instance.GetPropertyValue("_ImplicitlySkipAnalyzers"); diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.cs index 1168a7f9dc9ae..802cc4eb1389e 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.cs @@ -1333,10 +1333,11 @@ private ImmutableHashSet ComputeSuppressedAnalyzersForTree(S var hasUnsuppressedDiagnostic = false; foreach (var descriptor in descriptors) { - _ = options.TryGetGlobalDiagnosticValue(descriptor.Id, AnalyzerExecutor.CancellationToken, out var configuredSeverity); - if (options.TryGetDiagnosticValue(tree, descriptor.Id, AnalyzerExecutor.CancellationToken, out var diagnosticSeverity)) + var configuredSeverity = descriptor.GetEffectiveSeverity(AnalyzerExecutor.Compilation.Options); + if (options.TryGetDiagnosticValue(tree, descriptor.Id, AnalyzerExecutor.CancellationToken, out var severityFromOptions) || + options.TryGetGlobalDiagnosticValue(descriptor.Id, AnalyzerExecutor.CancellationToken, out severityFromOptions)) { - configuredSeverity = diagnosticSeverity; + configuredSeverity = severityFromOptions; } // Disabled by default descriptor with default configured severity is equivalent to suppressed. diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/DiagnosticAnalysisContext.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/DiagnosticAnalysisContext.cs index 3e388bebf0909..11d2f2ff2446d 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/DiagnosticAnalysisContext.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/DiagnosticAnalysisContext.cs @@ -542,6 +542,7 @@ public readonly struct CompilationAnalysisContext /// public CancellationToken CancellationToken { get { return _cancellationToken; } } + [Obsolete("Use CompilationWithAnalyzers instead. See https://github.com/dotnet/roslyn/issues/63440 for more details.")] public CompilationAnalysisContext(Compilation compilation, AnalyzerOptions options, Action reportDiagnostic, Func isSupportedDiagnostic, CancellationToken cancellationToken) : this(compilation, options, reportDiagnostic, isSupportedDiagnostic, null, cancellationToken) { @@ -658,7 +659,7 @@ public readonly struct SemanticModelAnalysisContext /// public bool IsGeneratedCode { get; } - // TODO: Mark obsolete, tracked with https://github.com/dotnet/roslyn/issues/63440 + [Obsolete("Use CompilationWithAnalyzers instead. See https://github.com/dotnet/roslyn/issues/63440 for more details.")] public SemanticModelAnalysisContext(SemanticModel semanticModel, AnalyzerOptions options, Action reportDiagnostic, Func isSupportedDiagnostic, CancellationToken cancellationToken) : this(semanticModel, options, reportDiagnostic, isSupportedDiagnostic, filterSpan: null, isGeneratedCode: false, cancellationToken) { @@ -736,7 +737,7 @@ public readonly struct SymbolAnalysisContext /// public bool IsGeneratedCode { get; } - // TODO: Mark obsolete, tracked with https://github.com/dotnet/roslyn/issues/63440 + [Obsolete("Use CompilationWithAnalyzers instead. See https://github.com/dotnet/roslyn/issues/63440 for more details.")] public SymbolAnalysisContext(ISymbol symbol, Compilation compilation, AnalyzerOptions options, Action reportDiagnostic, Func isSupportedDiagnostic, CancellationToken cancellationToken) : this(symbol, compilation, options, reportDiagnostic, isSupportedDiagnostic, isGeneratedCode: false, cancellationToken) { @@ -805,7 +806,7 @@ public abstract class SymbolStartAnalysisContext /// public CancellationToken CancellationToken { get; } - // TODO: Mark obsolete, tracked with https://github.com/dotnet/roslyn/issues/63440 + [Obsolete("Use CompilationWithAnalyzers instead. See https://github.com/dotnet/roslyn/issues/63440 for more details.")] public SymbolStartAnalysisContext(ISymbol symbol, Compilation compilation, AnalyzerOptions options, CancellationToken cancellationToken) : this(symbol, compilation, options, isGeneratedCode: false, cancellationToken) { @@ -954,7 +955,7 @@ public abstract class CodeBlockStartAnalysisContext where TLa /// public CancellationToken CancellationToken { get { return _cancellationToken; } } - // TODO: Mark obsolete, tracked with https://github.com/dotnet/roslyn/issues/63440 + [Obsolete("Use CompilationWithAnalyzers instead. See https://github.com/dotnet/roslyn/issues/63440 for more details.")] protected CodeBlockStartAnalysisContext(SyntaxNode codeBlock, ISymbol owningSymbol, SemanticModel semanticModel, AnalyzerOptions options, CancellationToken cancellationToken) : this(codeBlock, owningSymbol, semanticModel, options, isGeneratedCode: false, cancellationToken) { @@ -1049,7 +1050,7 @@ public readonly struct CodeBlockAnalysisContext /// public CancellationToken CancellationToken { get { return _cancellationToken; } } - // TODO: Mark obsolete, tracked with https://github.com/dotnet/roslyn/issues/63440 + [Obsolete("Use CompilationWithAnalyzers instead. See https://github.com/dotnet/roslyn/issues/63440 for more details.")] public CodeBlockAnalysisContext(SyntaxNode codeBlock, ISymbol owningSymbol, SemanticModel semanticModel, AnalyzerOptions options, Action reportDiagnostic, Func isSupportedDiagnostic, CancellationToken cancellationToken) : this(codeBlock, owningSymbol, semanticModel, options, reportDiagnostic, isSupportedDiagnostic, isGeneratedCode: false, cancellationToken) { @@ -1144,7 +1145,7 @@ public abstract class OperationBlockStartAnalysisContext /// public CancellationToken CancellationToken => _cancellationToken; - // TODO: Mark obsolete, tracked with https://github.com/dotnet/roslyn/issues/63440 + [Obsolete("Use CompilationWithAnalyzers instead. See https://github.com/dotnet/roslyn/issues/63440 for more details.")] protected OperationBlockStartAnalysisContext( ImmutableArray operationBlocks, ISymbol owningSymbol, @@ -1269,7 +1270,7 @@ public readonly struct OperationBlockAnalysisContext /// public CancellationToken CancellationToken => _cancellationToken; - // TODO: Mark obsolete, tracked with https://github.com/dotnet/roslyn/issues/63440 + [Obsolete("Use CompilationWithAnalyzers instead. See https://github.com/dotnet/roslyn/issues/63440 for more details.")] public OperationBlockAnalysisContext( ImmutableArray operationBlocks, ISymbol owningSymbol, @@ -1372,7 +1373,7 @@ public readonly struct SyntaxTreeAnalysisContext internal Compilation? Compilation => _compilationOpt; - // TODO: Mark obsolete, tracked with https://github.com/dotnet/roslyn/issues/63440 + [Obsolete("Use CompilationWithAnalyzers instead. See https://github.com/dotnet/roslyn/issues/63440 for more details.")] public SyntaxTreeAnalysisContext(SyntaxTree tree, AnalyzerOptions options, Action reportDiagnostic, Func isSupportedDiagnostic, CancellationToken cancellationToken) : this(tree, options, reportDiagnostic, isSupportedDiagnostic, compilation: null, isGeneratedCode: false, cancellationToken) { @@ -1519,13 +1520,13 @@ public readonly struct SyntaxNodeAnalysisContext /// public CancellationToken CancellationToken => _cancellationToken; - // TODO: Mark obsolete, tracked with https://github.com/dotnet/roslyn/issues/63440 + [Obsolete("Use CompilationWithAnalyzers instead. See https://github.com/dotnet/roslyn/issues/63440 for more details.")] public SyntaxNodeAnalysisContext(SyntaxNode node, ISymbol? containingSymbol, SemanticModel semanticModel, AnalyzerOptions options, Action reportDiagnostic, Func isSupportedDiagnostic, CancellationToken cancellationToken) : this(node, containingSymbol, semanticModel, options, reportDiagnostic, isSupportedDiagnostic, isGeneratedCode: false, cancellationToken) { } - // TODO: Mark obsolete, tracked with https://github.com/dotnet/roslyn/issues/63440 + [Obsolete("Use CompilationWithAnalyzers instead. See https://github.com/dotnet/roslyn/issues/63440 for more details.")] public SyntaxNodeAnalysisContext(SyntaxNode node, SemanticModel semanticModel, AnalyzerOptions options, Action reportDiagnostic, Func isSupportedDiagnostic, CancellationToken cancellationToken) : this(node, null, semanticModel, options, reportDiagnostic, isSupportedDiagnostic, isGeneratedCode: false, cancellationToken) { @@ -1610,7 +1611,7 @@ public readonly struct OperationAnalysisContext /// public CancellationToken CancellationToken => _cancellationToken; - // TODO: Mark obsolete, tracked with https://github.com/dotnet/roslyn/issues/63440 + [Obsolete("Use CompilationWithAnalyzers instead. See https://github.com/dotnet/roslyn/issues/63440 for more details.")] public OperationAnalysisContext( IOperation operation, ISymbol containingSymbol, diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs index 0d126d685b257..77e5d78ff0b4a 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs @@ -541,6 +541,8 @@ protected override void CreateIndicesForNonTypeMembers(ITypeDefinition typeDef) // First we find the deleted methods, and add them to our dictionary. This is used later when // processing events, properties, methods, and references. + ImmutableDictionary? deletedMethodDefinitions = null; + var deletedMethods = _changes.GetDeletedMethods(typeDef); if (deletedMethods.Length > 0) { @@ -551,7 +553,8 @@ protected override void CreateIndicesForNonTypeMembers(ITypeDefinition typeDef) deletedTypeMembers.Add(oldMethodDef, new DeletedMethodDefinition(oldMethodDef, typeDef, _typesUsedByDeletedMembers)); } - _deletedTypeMembers.Add(typeDef, deletedTypeMembers.ToImmutableDictionary()); + deletedMethodDefinitions = deletedTypeMembers.ToImmutableDictionary(); + _deletedTypeMembers.Add(typeDef, deletedMethodDefinitions); } foreach (var eventDef in typeDef.GetEvents(this.Context)) @@ -565,17 +568,17 @@ protected override void CreateIndicesForNonTypeMembers(ITypeDefinition typeDef) this.AddDefIfNecessary(_eventDefs, eventDef, eventChange); } - var deletedEvents = _changes.GetDeletedEvents(typeDef); - foreach (var eventDel in deletedEvents) + foreach (var eventDef in _changes.GetDeletedEvents(typeDef)) { - var oldEventDef = (IEventDefinition)eventDel.GetCciAdapter(); + RoslynDebug.AssertNotNull(deletedMethodDefinitions); + + var oldEventDef = (IEventDefinition)eventDef.GetCciAdapter(); // Because deleted event information comes from the associated symbol of the deleted accessors, its safe // to assume that everything will be in the dictionary. We wouldn't be here it if wasn't. - var deletedMembers = _deletedTypeMembers[typeDef]; - var adder = deletedMembers[(IMethodDefinition)oldEventDef.Adder]; - var remover = deletedMembers[(IMethodDefinition)oldEventDef.Remover]; - var caller = oldEventDef.Caller is null ? null : deletedMembers[(IMethodDefinition)oldEventDef.Caller]; + var adder = deletedMethodDefinitions[(IMethodDefinition)oldEventDef.Adder]; + var remover = deletedMethodDefinitions[(IMethodDefinition)oldEventDef.Remover]; + var caller = oldEventDef.Caller is null ? null : deletedMethodDefinitions[(IMethodDefinition)oldEventDef.Caller]; var newEventDef = new DeletedEventDefinition(oldEventDef, adder, remover, caller, typeDef, _typesUsedByDeletedMembers); _eventDefs.AddUpdated(newEventDef); } @@ -595,9 +598,9 @@ protected override void CreateIndicesForNonTypeMembers(ITypeDefinition typeDef) // Because we already processed the deleted methods above, this is a bit easier than // properties and events, and we just need to make sure we add the right indices - if (_deletedTypeMembers.ContainsKey(typeDef)) + if (deletedMethodDefinitions is not null) { - foreach (var (_, newMethodDef) in _deletedTypeMembers[typeDef]) + foreach (var (_, newMethodDef) in deletedMethodDefinitions) { _methodDefs.AddUpdated(newMethodDef); CreateIndicesForMethod(newMethodDef, SymbolChange.Updated); @@ -615,16 +618,16 @@ protected override void CreateIndicesForNonTypeMembers(ITypeDefinition typeDef) this.AddDefIfNecessary(_propertyDefs, propertyDef, propertyChange); } - var deletedProperties = _changes.GetDeletedProperties(typeDef); - foreach (var propertyDef in deletedProperties) + foreach (var propertyDef in _changes.GetDeletedProperties(typeDef)) { + RoslynDebug.AssertNotNull(deletedMethodDefinitions); + var oldPropertyDef = (IPropertyDefinition)propertyDef.GetCciAdapter(); // Because deleted property information comes from the associated symbol of the deleted accessors, its safe // to assume that everything will be in the dictionary. We wouldn't be here it if wasn't. - var deletedMembers = _deletedTypeMembers[typeDef]; - var getter = oldPropertyDef.Getter is null ? null : deletedMembers[(IMethodDefinition)oldPropertyDef.Getter]; - var setter = oldPropertyDef.Setter is null ? null : deletedMembers[(IMethodDefinition)oldPropertyDef.Setter]; + var getter = oldPropertyDef.Getter is null ? null : deletedMethodDefinitions[(IMethodDefinition)oldPropertyDef.Getter]; + var setter = oldPropertyDef.Setter is null ? null : deletedMethodDefinitions[(IMethodDefinition)oldPropertyDef.Setter]; var newPropertyDef = new DeletedPropertyDefinition(oldPropertyDef, getter, setter, typeDef, _typesUsedByDeletedMembers); _propertyDefs.AddUpdated(newPropertyDef); } @@ -669,7 +672,7 @@ protected override void CreateIndicesForNonTypeMembers(ITypeDefinition typeDef) implementingMethods.Free(); } - private bool DefinitionExistsInAnyPreviousGeneration(IDefinition item) => item switch + private bool DefinitionExistsInAnyPreviousGeneration(ITypeDefinitionMember item) => item switch { IMethodDefinition methodDef => TryGetExistingMethodDefIndex(methodDef, out _), IPropertyDefinition propertyDef => TryGetExistingPropertyDefIndex(propertyDef, out _), diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/SymbolChanges.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/SymbolChanges.cs index de2021913f91d..62af09ad4622e 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/SymbolChanges.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/SymbolChanges.cs @@ -70,6 +70,22 @@ public ImmutableDictionary> Get return builder.ToImmutable(); } + private ImmutableArray GetDeletedMemberInternalSymbols(IDefinition containingType, bool includeMethods, bool includeProperties, bool includeEvents) + { + var containingSymbol = containingType.GetInternalSymbol()?.GetISymbol(); + if (containingSymbol is null) + { + return ImmutableArray.Empty; + } + + if (!_deletedMembers.TryGetValue(containingSymbol, out var deleted)) + { + return ImmutableArray.Empty; + } + + return GetDeletedMemberInternalSymbols(deleted, includeMethods, includeProperties, includeEvents); + } + private ImmutableArray GetDeletedMemberInternalSymbols(ISet deletedMembers, bool includeMethods, bool includeProperties, bool includeEvents) { var internalSymbols = ArrayBuilder.GetInstance(); @@ -112,52 +128,13 @@ private ImmutableArray GetDeletedMemberInternalSymbols(ISet GetDeletedMethods(IDefinition containingType) - { - var containingSymbol = containingType.GetInternalSymbol()?.GetISymbol(); - if (containingSymbol is null) - { - return ImmutableArray.Empty; - } - - if (!_deletedMembers.TryGetValue(containingSymbol, out var deleted)) - { - return ImmutableArray.Empty; - } - - return GetDeletedMemberInternalSymbols(deleted, includeMethods: true, includeProperties: false, includeEvents: false); - } + => GetDeletedMemberInternalSymbols(containingType, includeMethods: true, includeProperties: false, includeEvents: false); public ImmutableArray GetDeletedProperties(IDefinition containingType) - { - var containingSymbol = containingType.GetInternalSymbol()?.GetISymbol(); - if (containingSymbol is null) - { - return ImmutableArray.Empty; - } - - if (!_deletedMembers.TryGetValue(containingSymbol, out var deleted)) - { - return ImmutableArray.Empty; - } - - return GetDeletedMemberInternalSymbols(deleted, includeMethods: false, includeProperties: true, includeEvents: false); - } + => GetDeletedMemberInternalSymbols(containingType, includeMethods: false, includeProperties: true, includeEvents: false); public ImmutableArray GetDeletedEvents(IDefinition containingType) - { - var containingSymbol = containingType.GetInternalSymbol()?.GetISymbol(); - if (containingSymbol is null) - { - return ImmutableArray.Empty; - } - - if (!_deletedMembers.TryGetValue(containingSymbol, out var deleted)) - { - return ImmutableArray.Empty; - } - - return GetDeletedMemberInternalSymbols(deleted, includeMethods: false, includeProperties: false, includeEvents: true); - } + => GetDeletedMemberInternalSymbols(containingType, includeMethods: false, includeProperties: false, includeEvents: true); public bool IsReplaced(IDefinition definition, bool checkEnclosingTypes = false) => definition.GetInternalSymbol() is { } internalSymbol && IsReplaced(internalSymbol.GetISymbol(), checkEnclosingTypes); @@ -384,13 +361,13 @@ private SymbolChange GetChange(ISymbol symbol) } } - public SymbolChange GetChangeForPossibleReAddedMember(IDefinition item, Func definitionExistsInAnyPreviousGeneration) + public SymbolChange GetChangeForPossibleReAddedMember(ITypeDefinitionMember item, Func definitionExistsInAnyPreviousGeneration) { var change = GetChange(item); return fixChangeIfMemberIsReAdded(item, change, definitionExistsInAnyPreviousGeneration); - SymbolChange fixChangeIfMemberIsReAdded(IDefinition item, SymbolChange change, Func definitionExistsInAnyPreviousGeneration) + SymbolChange fixChangeIfMemberIsReAdded(ITypeDefinitionMember item, SymbolChange change, Func definitionExistsInAnyPreviousGeneration) { // If this is a field that is being added, but it's part of a property or event that has been deleted // and is now being re-added, we don't want to add the field twice, so we ignore the change. @@ -399,7 +376,7 @@ SymbolChange fixChangeIfMemberIsReAdded(IDefinition item, SymbolChange change, F // This also makes sure to check that the field itself is being re-added, because it could be // a property that is being re-added as an auto-prop, when it wasn't one before, for example. if (item is IFieldDefinition fieldDefinition && - GetContainingDefinitionForBackingField(fieldDefinition) is IDefinition containingDef && + GetContainingDefinitionForBackingField(fieldDefinition) is ITypeDefinitionMember containingDef && GetChange(containingDef) == SymbolChange.Added && definitionExistsInAnyPreviousGeneration(item) && fixChangeIfMemberIsReAdded(containingDef, SymbolChange.Added, definitionExistsInAnyPreviousGeneration) == SymbolChange.Updated) @@ -412,8 +389,7 @@ SymbolChange fixChangeIfMemberIsReAdded(IDefinition item, SymbolChange change, F // deleted in a generation, and then "added" in a subsequent one, but that is an update // even if the previous generation doesn't know about it. if (change == SymbolChange.Added && - item is ITypeDefinitionMember member && - !IsReplaced(member.ContainingTypeDefinition, checkEnclosingTypes: true) && + !IsReplaced(item.ContainingTypeDefinition, checkEnclosingTypes: true) && definitionExistsInAnyPreviousGeneration(item)) { return SymbolChange.Updated; diff --git a/src/Compilers/Core/Portable/MetadataReference/MetadataReference.cs b/src/Compilers/Core/Portable/MetadataReference/MetadataReference.cs index 76d3d5226fc8a..faa74f51029b3 100644 --- a/src/Compilers/Core/Portable/MetadataReference/MetadataReference.cs +++ b/src/Compilers/Core/Portable/MetadataReference/MetadataReference.cs @@ -122,7 +122,12 @@ public static PortableExecutableReference CreateFromImage( DocumentationProvider? documentation = null, string? filePath = null) { - var metadata = AssemblyMetadata.CreateFromImage(peImage); + Metadata metadata = properties.Kind switch + { + MetadataImageKind.Module => ModuleMetadata.CreateFromImage(peImage), + _ => AssemblyMetadata.CreateFromImage(peImage), + }; + return new MetadataImageReference(metadata, properties, documentation, filePath, display: null); } @@ -155,7 +160,12 @@ public static PortableExecutableReference CreateFromImage( DocumentationProvider? documentation = null, string? filePath = null) { - var metadata = AssemblyMetadata.CreateFromImage(peImage); + Metadata metadata = properties.Kind switch + { + MetadataImageKind.Module => ModuleMetadata.CreateFromImage(peImage), + _ => AssemblyMetadata.CreateFromImage(peImage), + }; + return new MetadataImageReference(metadata, properties, documentation, filePath, display: null); } @@ -193,7 +203,11 @@ public static PortableExecutableReference CreateFromStream( string? filePath = null) { // Prefetch data and close the stream. - var metadata = AssemblyMetadata.CreateFromStream(peStream, PEStreamOptions.PrefetchEntireImage); + Metadata metadata = properties.Kind switch + { + MetadataImageKind.Module => ModuleMetadata.CreateFromStream(peStream, PEStreamOptions.PrefetchEntireImage), + _ => AssemblyMetadata.CreateFromStream(peStream, PEStreamOptions.PrefetchEntireImage), + }; return new MetadataImageReference(metadata, properties, documentation, filePath, display: null); } diff --git a/src/Compilers/Core/Portable/Microsoft.CodeAnalysis.csproj b/src/Compilers/Core/Portable/Microsoft.CodeAnalysis.csproj index 090dcf544b8b9..c70dd78a49c04 100644 --- a/src/Compilers/Core/Portable/Microsoft.CodeAnalysis.csproj +++ b/src/Compilers/Core/Portable/Microsoft.CodeAnalysis.csproj @@ -26,16 +26,16 @@ - + - + @@ -80,6 +80,7 @@ + diff --git a/src/Compilers/Core/Portable/SourceGeneration/GeneratorDriver.cs b/src/Compilers/Core/Portable/SourceGeneration/GeneratorDriver.cs index aff21470866e5..cfa13bb7f0015 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/GeneratorDriver.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/GeneratorDriver.cs @@ -163,7 +163,8 @@ public GeneratorDriverRunResult GetRunResult() generatedSources: getGeneratorSources(generatorState), elapsedTime: generatorState.ElapsedTime, namedSteps: generatorState.ExecutedSteps, - outputSteps: generatorState.OutputSteps)); + outputSteps: generatorState.OutputSteps, + hostOutputs: generatorState.HostOutputs)); return new GeneratorDriverRunResult(results, _state.RunTime); static ImmutableArray getGeneratorSources(GeneratorState generatorState) @@ -293,10 +294,10 @@ internal GeneratorDriverState RunGeneratorsCore(Compilation compilation, Diagnos { // We do not support incremental step tracking for v1 generators, as the pipeline is implicitly defined. var context = UpdateOutputs(generatorState.OutputNodes, IncrementalGeneratorOutputKind.Source | IncrementalGeneratorOutputKind.Implementation, new GeneratorRunStateTable.Builder(state.TrackIncrementalSteps), cancellationToken, driverStateBuilder); - (var sources, var generatorDiagnostics, var generatorRunStateTable) = context.ToImmutableAndFree(); + (var sources, var generatorDiagnostics, var generatorRunStateTable, var hostOutputs) = context.ToImmutableAndFree(); generatorDiagnostics = FilterDiagnostics(compilation, generatorDiagnostics, driverDiagnostics: diagnosticsBag, cancellationToken); - stateBuilder[i] = generatorState.WithResults(ParseAdditionalSources(state.Generators[i], sources, cancellationToken), generatorDiagnostics, generatorRunStateTable.ExecutedSteps, generatorRunStateTable.OutputSteps, generatorTimer.Elapsed); + stateBuilder[i] = generatorState.WithResults(ParseAdditionalSources(state.Generators[i], sources, cancellationToken), generatorDiagnostics, generatorRunStateTable.ExecutedSteps, generatorRunStateTable.OutputSteps, hostOutputs, generatorTimer.Elapsed); } catch (UserFunctionException ufe) { diff --git a/src/Compilers/Core/Portable/SourceGeneration/GeneratorState.cs b/src/Compilers/Core/Portable/SourceGeneration/GeneratorState.cs index 72ae1a1daa884..1ddc1cc5692a4 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/GeneratorState.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/GeneratorState.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Immutable; using System.Diagnostics; + namespace Microsoft.CodeAnalysis { /// @@ -20,6 +21,7 @@ internal readonly struct GeneratorState ImmutableArray.Empty, ImmutableDictionary>.Empty, ImmutableDictionary>.Empty, + ImmutableArray<(string, string)>.Empty, exception: null, elapsedTime: TimeSpan.Zero); @@ -27,11 +29,30 @@ internal readonly struct GeneratorState /// Creates a new generator state that contains information, constant trees and an execution pipeline /// public GeneratorState(ImmutableArray postInitTrees, ImmutableArray inputNodes, ImmutableArray outputNodes) - : this(postInitTrees, inputNodes, outputNodes, ImmutableArray.Empty, ImmutableArray.Empty, ImmutableDictionary>.Empty, ImmutableDictionary>.Empty, exception: null, elapsedTime: TimeSpan.Zero) + : this(postInitTrees, + inputNodes, + outputNodes, + ImmutableArray.Empty, + ImmutableArray.Empty, + ImmutableDictionary>.Empty, + ImmutableDictionary>.Empty, + ImmutableArray<(string, string)>.Empty, + exception: null, + elapsedTime: TimeSpan.Zero) { } - private GeneratorState(ImmutableArray postInitTrees, ImmutableArray inputNodes, ImmutableArray outputNodes, ImmutableArray generatedTrees, ImmutableArray diagnostics, ImmutableDictionary> executedSteps, ImmutableDictionary> outputSteps, Exception? exception, TimeSpan elapsedTime) + private GeneratorState( + ImmutableArray postInitTrees, + ImmutableArray inputNodes, + ImmutableArray outputNodes, + ImmutableArray generatedTrees, + ImmutableArray diagnostics, + ImmutableDictionary> executedSteps, + ImmutableDictionary> outputSteps, + ImmutableArray<(string Key, string Value)> hostOutputs, + Exception? exception, + TimeSpan elapsedTime) { this.Initialized = true; this.PostInitTrees = postInitTrees; @@ -41,6 +62,7 @@ private GeneratorState(ImmutableArray postInitTrees, Immuta this.Diagnostics = diagnostics; this.ExecutedSteps = executedSteps; this.OutputSteps = outputSteps; + this.HostOutputs = hostOutputs; this.Exception = exception; this.ElapsedTime = elapsedTime; } @@ -49,6 +71,7 @@ public GeneratorState WithResults(ImmutableArray generatedT ImmutableArray diagnostics, ImmutableDictionary> executedSteps, ImmutableDictionary> outputSteps, + ImmutableArray<(string Key, string Value)> hostOutputs, TimeSpan elapsedTime) { return new GeneratorState(this.PostInitTrees, @@ -58,6 +81,7 @@ public GeneratorState WithResults(ImmutableArray generatedT diagnostics, executedSteps, outputSteps, + hostOutputs, exception: null, elapsedTime); } @@ -71,6 +95,7 @@ public GeneratorState WithError(Exception exception, Diagnostic error, TimeSpan ImmutableArray.Create(error), ImmutableDictionary>.Empty, ImmutableDictionary>.Empty, + ImmutableArray<(string, string)>.Empty, exception, elapsedTime); } @@ -94,5 +119,7 @@ public GeneratorState WithError(Exception exception, Diagnostic error, TimeSpan internal ImmutableDictionary> ExecutedSteps { get; } internal ImmutableDictionary> OutputSteps { get; } + + internal ImmutableArray<(string Key, string Value)> HostOutputs { get; } } } diff --git a/src/Compilers/Core/Portable/SourceGeneration/IncrementalContexts.cs b/src/Compilers/Core/Portable/SourceGeneration/IncrementalContexts.cs index 56988c5b19c25..aeecf8e0cf1a0 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/IncrementalContexts.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/IncrementalContexts.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Generic; using System.Collections.Immutable; using System.Text; using System.Threading; @@ -166,16 +167,19 @@ internal readonly struct IncrementalExecutionContext internal readonly GeneratorRunStateTable.Builder GeneratorRunStateBuilder; + internal readonly ArrayBuilder<(string Key, string Value)> HostOutputBuilder; + public IncrementalExecutionContext(DriverStateTable.Builder? tableBuilder, GeneratorRunStateTable.Builder generatorRunStateBuilder, AdditionalSourcesCollection sources) { TableBuilder = tableBuilder; GeneratorRunStateBuilder = generatorRunStateBuilder; Sources = sources; + HostOutputBuilder = ArrayBuilder<(string, string)>.GetInstance(); Diagnostics = DiagnosticBag.GetInstance(); } - internal (ImmutableArray sources, ImmutableArray diagnostics, GeneratorRunStateTable executedSteps) ToImmutableAndFree() - => (Sources.ToImmutableAndFree(), Diagnostics.ToReadOnlyAndFree(), GeneratorRunStateBuilder.ToImmutableAndFree()); + internal (ImmutableArray sources, ImmutableArray diagnostics, GeneratorRunStateTable executedSteps, ImmutableArray<(string Key, string Value)> hostOutputs) ToImmutableAndFree() + => (Sources.ToImmutableAndFree(), Diagnostics.ToReadOnlyAndFree(), GeneratorRunStateBuilder.ToImmutableAndFree(), HostOutputBuilder.ToImmutableAndFree()); internal void Free() { diff --git a/src/Compilers/Core/Portable/SourceGeneration/RunResults.cs b/src/Compilers/Core/Portable/SourceGeneration/RunResults.cs index dda8cb5da2406..c95d9c2f966fb 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/RunResults.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/RunResults.cs @@ -77,7 +77,15 @@ public ImmutableArray GeneratedTrees /// public readonly struct GeneratorRunResult { - internal GeneratorRunResult(ISourceGenerator generator, ImmutableArray generatedSources, ImmutableArray diagnostics, ImmutableDictionary> namedSteps, ImmutableDictionary> outputSteps, Exception? exception, TimeSpan elapsedTime) + internal GeneratorRunResult( + ISourceGenerator generator, + ImmutableArray generatedSources, + ImmutableArray diagnostics, + ImmutableDictionary> namedSteps, + ImmutableDictionary> outputSteps, + ImmutableArray<(string Key, string Value)> hostOutputs, + Exception? exception, + TimeSpan elapsedTime) { Debug.Assert(exception is null || (generatedSources.IsEmpty && diagnostics.Length == 1)); @@ -86,6 +94,7 @@ internal GeneratorRunResult(ISourceGenerator generator, ImmutableArray public ImmutableArray Diagnostics { get; } + internal ImmutableArray<(string Key, string Value)> HostOutputs { get; } + /// /// An instance that was thrown by the generator, or null if the generator completed without error. /// diff --git a/src/Compilers/Core/Portable/WellKnownMember.cs b/src/Compilers/Core/Portable/WellKnownMember.cs index 6bdd52e00f151..0e1041269ed3f 100644 --- a/src/Compilers/Core/Portable/WellKnownMember.cs +++ b/src/Compilers/Core/Portable/WellKnownMember.cs @@ -55,6 +55,7 @@ internal enum WellKnownMember System_Type__GetTypeFromHandle, System_Type__Missing, System_Type__op_Equality, + System_Type__get_IsValueType, System_Reflection_AssemblyKeyFileAttribute__ctor, System_Reflection_AssemblyKeyNameAttribute__ctor, diff --git a/src/Compilers/Core/Portable/WellKnownMembers.cs b/src/Compilers/Core/Portable/WellKnownMembers.cs index 3e354d75e2ed9..827156a0474e5 100644 --- a/src/Compilers/Core/Portable/WellKnownMembers.cs +++ b/src/Compilers/Core/Portable/WellKnownMembers.cs @@ -365,6 +365,13 @@ static WellKnownMembers() (byte)SignatureTypeCode.TypeHandle, (byte)WellKnownType.System_Type, (byte)SignatureTypeCode.TypeHandle, (byte)WellKnownType.System_Type, + // System_Type__get_IsValueType + (byte)(MemberFlags.PropertyGet), // Flags + (byte)WellKnownType.System_Type, // DeclaringTypeId + 0, // Arity + 0, // Method Signature + (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Boolean, // Return Type + // System_Reflection_AssemblyKeyFileAttribute__ctor (byte)MemberFlags.Constructor, // Flags (byte)WellKnownType.System_Reflection_AssemblyKeyFileAttribute, // DeclaringTypeId @@ -3727,6 +3734,7 @@ static WellKnownMembers() "GetTypeFromHandle", // System_Type__GetTypeFromHandle "Missing", // System_Type__Missing WellKnownMemberNames.EqualityOperatorName, // System_Type__op_Equality + "get_IsValueType", // System_Type__get_IsValueType ".ctor", // System_Reflection_AssemblyKeyFileAttribute__ctor ".ctor", // System_Reflection_AssemblyKeyNameAttribute__ctor "GetMethodFromHandle", // System_Reflection_MethodBase__GetMethodFromHandle diff --git a/src/Compilers/Test/Core/Assert/AssertEx.cs b/src/Compilers/Test/Core/Assert/AssertEx.cs index 8ecce2e8c022b..365df6758ee91 100644 --- a/src/Compilers/Test/Core/Assert/AssertEx.cs +++ b/src/Compilers/Test/Core/Assert/AssertEx.cs @@ -37,7 +37,7 @@ public static class AssertEx private class AssertEqualityComparer : IEqualityComparer { - private static readonly IEqualityComparer s_instance = new AssertEqualityComparer(); + public static readonly IEqualityComparer Instance = new AssertEqualityComparer(); private static bool CanBeNull() { @@ -58,7 +58,7 @@ public static bool IsNull(T @object) public static bool Equals(T left, T right) { - return s_instance.Equals(left, right); + return Instance.Equals(left, right); } bool IEqualityComparer.Equals(T x, T y) @@ -141,23 +141,30 @@ public static void AreEqual(T expected, T actual, string message = null, IEqu if (expected == null) { - Fail("expected was null, but actual wasn't\r\n" + message); + Fail("expected was null, but actual wasn't" + Environment.NewLine + message); } else if (actual == null) { - Fail("actual was null, but expected wasn't\r\n" + message); + Fail("actual was null, but expected wasn't" + Environment.NewLine + message); } - else + else if (!(comparer ?? AssertEqualityComparer.Instance).Equals(expected, actual)) { - if (!(comparer != null ? - comparer.Equals(expected, actual) : - AssertEqualityComparer.Equals(expected, actual))) + string expectedAndActual; + if (expected is IEnumerable expectedEnumerable && actual is IEnumerable actualEnumerable) { - Fail("Expected and actual were different.\r\n" + - "Expected:\r\n" + expected + "\r\n" + - "Actual:\r\n" + actual + "\r\n" + - message); + expectedAndActual = GetAssertMessage(expectedEnumerable.OfType(), actualEnumerable.OfType(), comparer: null); } + else + { + expectedAndActual = $""" + Expected: + {expected} + Actual: + {actual} + """; + } + + Fail(message + Environment.NewLine + expectedAndActual); } } diff --git a/src/Compilers/VisualBasic/Portable/CodeGen/EmitExpression.vb b/src/Compilers/VisualBasic/Portable/CodeGen/EmitExpression.vb index 9ff4c8ac37b47..82126ab729acf 100644 --- a/src/Compilers/VisualBasic/Portable/CodeGen/EmitExpression.vb +++ b/src/Compilers/VisualBasic/Portable/CodeGen/EmitExpression.vb @@ -287,7 +287,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen ' Or if we have a ref-constrained T (to do box just once) Dim receiver As BoundExpression = conditional.ReceiverOrCondition Dim receiverType As TypeSymbol = receiver.Type - Dim nullCheckOnCopy = conditional.CaptureReceiver OrElse (receiverType.IsReferenceType AndAlso receiverType.TypeKind = TypeKind.TypeParameter) + Dim nullCheckOnCopy = (Not receiverType.IsReferenceType AndAlso + Not receiverType.IsValueType AndAlso + Not DirectCast(receiverType, TypeParameterSymbol).HasInterfaceConstraint) OrElse ' This could be a nullable value type, which must be copied in order to not mutate the original value + conditional.CaptureReceiver OrElse + (receiverType.IsReferenceType AndAlso receiverType.TypeKind = TypeKind.TypeParameter) If nullCheckOnCopy Then receiverTemp = EmitReceiverRef(receiver, isAccessConstrained:=Not receiverType.IsReferenceType, addressKind:=AddressKind.ReadOnly) diff --git a/src/Compilers/VisualBasic/Portable/Symbols/ConstraintsHelper.vb b/src/Compilers/VisualBasic/Portable/Symbols/ConstraintsHelper.vb index 1ae4a479da2c6..4fa27b739b3a0 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/ConstraintsHelper.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/ConstraintsHelper.vb @@ -759,6 +759,30 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return result End Function + + Public Function HasInterfaceConstraint(typeParameter As TypeParameterSymbol) As Boolean + Dim result As TypeSymbol = Nothing + + For Each constraint In typeParameter.ConstraintTypesNoUseSiteDiagnostics + Select Case constraint.Kind + Case SymbolKind.ErrorType + Continue For + + Case SymbolKind.TypeParameter + If DirectCast(constraint, TypeParameterSymbol).HasInterfaceConstraint() Then + Return True + End If + + Case Else + If constraint.IsInterfaceType() Then + Return True + End If + End Select + Next + + Return False + End Function + ''' ''' Return the most derived class type from the set of constraint types on this type ''' parameter and any type parameter it depends on. Returns Nothing if there are diff --git a/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTests.vb b/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTests.vb index fd213fc1e9a99..8d9e885fbf753 100644 --- a/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTests.vb @@ -13995,25 +13995,25 @@ End Module c.VerifyIL("Module1.Test", ) End Sub diff --git a/src/Compilers/VisualBasic/Test/Semantic/Semantics/ConditionalAccessTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Semantics/ConditionalAccessTests.vb index e74b0f6a691da..acb1b677738f8 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Semantics/ConditionalAccessTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Semantics/ConditionalAccessTests.vb @@ -5507,32 +5507,42 @@ End Module 0 -1 +0 hello hello") c.VerifyIL("C(Of T).Print()", ) End Sub @@ -10335,5 +10345,165 @@ End Class }") End Sub + + + Public Sub NullableSideEffects_01() + Dim c = CompileAndVerify( + + +Structure S1 + private count As Integer + Public Overrides Function ToString() As String + count+=1 + Return count.ToString() + End Function +End Structure + +Class Program + Shared Sub Main() + Dim x1 As new S1?(new S1()) + System.Console.Write(Test1(x1)) + System.Console.Write(x1.ToString()) + x1 = Nothing + System.Console.Write(Test1(x1) is Nothing) + End Sub + + Shared Function Test1(Of T)(ByRef x As T) As String + return x?.ToString() + End Function +End Class + +, expectedOutput:="11True").VerifyDiagnostics() + + c.VerifyIL("Program.Test1(Of T)(ByRef T)", + ) + End Sub + + + + Public Sub NullableSideEffects_02() + Dim c = CompileAndVerify( + + +Structure S1 + private count As Integer + Public Overrides Function ToString() As String + count+=1 + Return count.ToString() + End Function +End Structure + +Class Program + Shared Sub Main() + Dim x1 As new S1?(new S1()) + System.Console.Write(Test1(x1)) + System.Console.Write(x1.ToString()) + x1 = Nothing + System.Console.Write(Test1(x1) is Nothing) + End Sub + + Shared Function Test1(Of T)(ByRef x As T) As String + Dim y = x + Dim result = y?.ToString() + x = y + Return result + End Function +End Class + +, expectedOutput:="11True").VerifyDiagnostics() + + c.VerifyIL("Program.Test1(Of T)(ByRef T)", + ) + End Sub + + + + Public Sub NullableSideEffects_03() + Dim c = CreateCompilation( + + +Structure S1 +End Structure + +MustInherit Class C0(Of U) + MustOverride Function Test1(Of T As U)(ByRef x As T) As String +End Class + +Class C1 + Inherits C0(Of S1?) + + Overrides Function Test1(Of T As S1?)(ByRef x As T) As String + Dim y = x + Dim result = y?.ToString() + x = y + Return result + End Function +End Class + +) + + c.AssertTheseEmitDiagnostics( + +BC30487: Operator '?' is not defined for type 'T'. + Dim result = y?.ToString() + ~ +) + End Sub + End Class End Namespace diff --git a/src/EditorFeatures/CSharp/AddImports/CSharpAddImportPlacementOptionsStorage.cs b/src/EditorFeatures/CSharp/AddImports/CSharpAddImportPlacementOptionsStorage.cs deleted file mode 100644 index dc0dd06280961..0000000000000 --- a/src/EditorFeatures/CSharp/AddImports/CSharpAddImportPlacementOptionsStorage.cs +++ /dev/null @@ -1,38 +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.Composition; -using Microsoft.CodeAnalysis.AddImport; -using Microsoft.CodeAnalysis.CSharp.CodeStyle; -using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Simplification; - -namespace Microsoft.CodeAnalysis.CSharp.AddImport; - -internal class CSharpAddImportPlacementOptionsStorage -{ - [ExportLanguageService(typeof(IAddImportPlacementOptionsStorage), LanguageNames.CSharp), Shared] - private sealed class Service : IAddImportPlacementOptionsStorage - { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public Service() - { - } - - public AddImportPlacementOptions GetOptions(IGlobalOptionService globalOptions) - => GetCSharpAddImportPlacementOptions(globalOptions); - } - - internal static AddImportPlacementOptions GetCSharpAddImportPlacementOptions(IGlobalOptionService globalOptions) - => new() - { - PlaceSystemNamespaceFirst = globalOptions.GetOption(GenerationOptions.PlaceSystemNamespaceFirst, LanguageNames.CSharp), - UsingDirectivePlacement = globalOptions.GetOption(CSharpCodeStyleOptions.PreferredUsingDirectivePlacement), - AllowInHiddenRegions = AddImportPlacementOptions.Default.AllowInHiddenRegions // no global option available); - }; -} diff --git a/src/EditorFeatures/CSharp/CodeGeneration/CSharpCodeGenerationOptionsStorage.cs b/src/EditorFeatures/CSharp/CodeGeneration/CSharpCodeGenerationOptionsStorage.cs deleted file mode 100644 index 6066335b7f7c0..0000000000000 --- a/src/EditorFeatures/CSharp/CodeGeneration/CSharpCodeGenerationOptionsStorage.cs +++ /dev/null @@ -1,44 +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.Composition; -using Microsoft.CodeAnalysis.CodeGeneration; -using Microsoft.CodeAnalysis.CSharp.CodeStyle; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; - -namespace Microsoft.CodeAnalysis.CSharp.CodeGeneration; - -internal static class CSharpCodeGenerationOptionsStorage -{ - [ExportLanguageService(typeof(ICodeGenerationOptionsStorage), LanguageNames.CSharp), Shared] - private sealed class Service : ICodeGenerationOptionsStorage - { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public Service() - { - } - - public CodeGenerationOptions GetOptions(IGlobalOptionService globalOptions) - => GetCSharpCodeGenerationOptions(globalOptions); - } - - public static CSharpCodeGenerationOptions GetCSharpCodeGenerationOptions(this IGlobalOptionService globalOptions) - => new() - { - Common = globalOptions.GetCommonCodeGenerationOptions(LanguageNames.CSharp), - PreferExpressionBodiedMethods = globalOptions.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedMethods), - PreferExpressionBodiedAccessors = globalOptions.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedAccessors), - PreferExpressionBodiedProperties = globalOptions.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedProperties), - PreferExpressionBodiedIndexers = globalOptions.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedIndexers), - PreferExpressionBodiedConstructors = globalOptions.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedConstructors), - PreferExpressionBodiedOperators = globalOptions.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedOperators), - PreferExpressionBodiedLocalFunctions = globalOptions.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedLocalFunctions), - PreferExpressionBodiedLambdas = globalOptions.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedLambdas), - PreferStaticLocalFunction = globalOptions.GetOption(CSharpCodeStyleOptions.PreferStaticLocalFunction), - NamespaceDeclarations = globalOptions.GetOption(CSharpCodeStyleOptions.NamespaceDeclarations) - }; -} diff --git a/src/EditorFeatures/CSharp/CodeStyle/CSharpCodeStyleOptionsStorage.cs b/src/EditorFeatures/CSharp/CodeStyle/CSharpCodeStyleOptionsStorage.cs deleted file mode 100644 index 5097075f022b9..0000000000000 --- a/src/EditorFeatures/CSharp/CodeStyle/CSharpCodeStyleOptionsStorage.cs +++ /dev/null @@ -1,62 +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.Composition; -using Microsoft.CodeAnalysis.CodeStyle; -using Microsoft.CodeAnalysis.CSharp.CodeStyle; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; - -namespace Microsoft.CodeAnalysis.CSharp.CodeStyle; - -internal static class CSharpCodeStyleOptionsStorage -{ - [ExportLanguageService(typeof(ICodeStyleOptionsStorage), LanguageNames.CSharp), Shared] - private sealed class Service : ICodeStyleOptionsStorage - { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public Service() - { - } - - public IdeCodeStyleOptions GetOptions(IGlobalOptionService globalOptions) - => GetCSharpCodeStyleOptions(globalOptions); - } - - public static CSharpIdeCodeStyleOptions GetCSharpCodeStyleOptions(this IGlobalOptionService globalOptions) - => new() - { - Common = globalOptions.GetCommonCodeStyleOptions(LanguageNames.CSharp), - ImplicitObjectCreationWhenTypeIsApparent = globalOptions.GetOption(CSharpCodeStyleOptions.ImplicitObjectCreationWhenTypeIsApparent), - PreferNullCheckOverTypeCheck = globalOptions.GetOption(CSharpCodeStyleOptions.PreferNullCheckOverTypeCheck), - AllowBlankLinesBetweenConsecutiveBraces = globalOptions.GetOption(CSharpCodeStyleOptions.AllowBlankLinesBetweenConsecutiveBraces), - AllowBlankLineAfterColonInConstructorInitializer = globalOptions.GetOption(CSharpCodeStyleOptions.AllowBlankLineAfterColonInConstructorInitializer), - AllowBlankLineAfterTokenInConditionalExpression = globalOptions.GetOption(CSharpCodeStyleOptions.AllowBlankLineAfterTokenInConditionalExpression), - AllowBlankLineAfterTokenInArrowExpressionClause = globalOptions.GetOption(CSharpCodeStyleOptions.AllowBlankLineAfterTokenInArrowExpressionClause), - PreferConditionalDelegateCall = globalOptions.GetOption(CSharpCodeStyleOptions.PreferConditionalDelegateCall), - PreferSwitchExpression = globalOptions.GetOption(CSharpCodeStyleOptions.PreferSwitchExpression), - PreferPatternMatching = globalOptions.GetOption(CSharpCodeStyleOptions.PreferPatternMatching), - PreferPatternMatchingOverAsWithNullCheck = globalOptions.GetOption(CSharpCodeStyleOptions.PreferPatternMatchingOverAsWithNullCheck), - PreferPatternMatchingOverIsWithCastCheck = globalOptions.GetOption(CSharpCodeStyleOptions.PreferPatternMatchingOverIsWithCastCheck), - PreferNotPattern = globalOptions.GetOption(CSharpCodeStyleOptions.PreferNotPattern), - PreferExtendedPropertyPattern = globalOptions.GetOption(CSharpCodeStyleOptions.PreferExtendedPropertyPattern), - PreferInlinedVariableDeclaration = globalOptions.GetOption(CSharpCodeStyleOptions.PreferInlinedVariableDeclaration), - PreferDeconstructedVariableDeclaration = globalOptions.GetOption(CSharpCodeStyleOptions.PreferDeconstructedVariableDeclaration), - PreferIndexOperator = globalOptions.GetOption(CSharpCodeStyleOptions.PreferIndexOperator), - PreferRangeOperator = globalOptions.GetOption(CSharpCodeStyleOptions.PreferRangeOperator), - PreferUtf8StringLiterals = globalOptions.GetOption(CSharpCodeStyleOptions.PreferUtf8StringLiterals), - PreferredModifierOrder = globalOptions.GetOption(CSharpCodeStyleOptions.PreferredModifierOrder), - PreferSimpleUsingStatement = globalOptions.GetOption(CSharpCodeStyleOptions.PreferSimpleUsingStatement), - PreferLocalOverAnonymousFunction = globalOptions.GetOption(CSharpCodeStyleOptions.PreferLocalOverAnonymousFunction), - PreferTupleSwap = globalOptions.GetOption(CSharpCodeStyleOptions.PreferTupleSwap), - UnusedValueExpressionStatement = globalOptions.GetOption(CSharpCodeStyleOptions.UnusedValueExpressionStatement), - UnusedValueAssignment = globalOptions.GetOption(CSharpCodeStyleOptions.UnusedValueAssignment), - PreferMethodGroupConversion = globalOptions.GetOption(CSharpCodeStyleOptions.PreferMethodGroupConversion), - PreferExpressionBodiedLambdas = globalOptions.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedLambdas), - PreferReadOnlyStruct = globalOptions.GetOption(CSharpCodeStyleOptions.PreferReadOnlyStruct), - PreferStaticLocalFunction = globalOptions.GetOption(CSharpCodeStyleOptions.PreferStaticLocalFunction) - }; -} diff --git a/src/EditorFeatures/CSharp/Formatting/CSharpSyntaxFormattingOptionsStorage.cs b/src/EditorFeatures/CSharp/Formatting/CSharpSyntaxFormattingOptionsStorage.cs deleted file mode 100644 index 1fb25372b00e6..0000000000000 --- a/src/EditorFeatures/CSharp/Formatting/CSharpSyntaxFormattingOptionsStorage.cs +++ /dev/null @@ -1,89 +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.Composition; -using Microsoft.CodeAnalysis.CodeStyle; -using Microsoft.CodeAnalysis.CSharp.CodeStyle; -using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Simplification; - -namespace Microsoft.CodeAnalysis.CSharp.Formatting; - -internal static class CSharpSyntaxFormattingOptionsStorage -{ - [ExportLanguageService(typeof(ISyntaxFormattingOptionsStorage), LanguageNames.CSharp), Shared] - private sealed class Service : ISyntaxFormattingOptionsStorage - { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public Service() - { - } - - public SyntaxFormattingOptions GetOptions(IGlobalOptionService globalOptions) - => GetCSharpSyntaxFormattingOptions(globalOptions); - } - - public static CSharpSyntaxFormattingOptions GetCSharpSyntaxFormattingOptions(this IGlobalOptionService globalOptions) - => new() - { - Common = globalOptions.GetCommonSyntaxFormattingOptions(LanguageNames.CSharp), - Spacing = - (globalOptions.GetOption(CSharpFormattingOptions2.SpacesIgnoreAroundVariableDeclaration) ? SpacePlacement.IgnoreAroundVariableDeclaration : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.SpacingAfterMethodDeclarationName) ? SpacePlacement.AfterMethodDeclarationName : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.SpaceBetweenEmptyMethodDeclarationParentheses) ? SpacePlacement.BetweenEmptyMethodDeclarationParentheses : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.SpaceWithinMethodDeclarationParenthesis) ? SpacePlacement.WithinMethodDeclarationParenthesis : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.SpaceAfterMethodCallName) ? SpacePlacement.AfterMethodCallName : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.SpaceBetweenEmptyMethodCallParentheses) ? SpacePlacement.BetweenEmptyMethodCallParentheses : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.SpaceWithinMethodCallParentheses) ? SpacePlacement.WithinMethodCallParentheses : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.SpaceAfterControlFlowStatementKeyword) ? SpacePlacement.AfterControlFlowStatementKeyword : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.SpaceWithinExpressionParentheses) ? SpacePlacement.WithinExpressionParentheses : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.SpaceWithinCastParentheses) ? SpacePlacement.WithinCastParentheses : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.SpaceBeforeSemicolonsInForStatement) ? SpacePlacement.BeforeSemicolonsInForStatement : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.SpaceAfterSemicolonsInForStatement) ? SpacePlacement.AfterSemicolonsInForStatement : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.SpaceWithinOtherParentheses) ? SpacePlacement.WithinOtherParentheses : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.SpaceAfterCast) ? SpacePlacement.AfterCast : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.SpaceBeforeOpenSquareBracket) ? SpacePlacement.BeforeOpenSquareBracket : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.SpaceBetweenEmptySquareBrackets) ? SpacePlacement.BetweenEmptySquareBrackets : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.SpaceWithinSquareBrackets) ? SpacePlacement.WithinSquareBrackets : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.SpaceAfterColonInBaseTypeDeclaration) ? SpacePlacement.AfterColonInBaseTypeDeclaration : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.SpaceBeforeColonInBaseTypeDeclaration) ? SpacePlacement.BeforeColonInBaseTypeDeclaration : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.SpaceAfterComma) ? SpacePlacement.AfterComma : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.SpaceBeforeComma) ? SpacePlacement.BeforeComma : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.SpaceAfterDot) ? SpacePlacement.AfterDot : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.SpaceBeforeDot) ? SpacePlacement.BeforeDot : 0), - SpacingAroundBinaryOperator = globalOptions.GetOption(CSharpFormattingOptions2.SpacingAroundBinaryOperator), - NewLines = - (globalOptions.GetOption(CSharpFormattingOptions2.NewLineForMembersInObjectInit) ? NewLinePlacement.BeforeMembersInObjectInitializers : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.NewLineForMembersInAnonymousTypes) ? NewLinePlacement.BeforeMembersInAnonymousTypes : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.NewLineForElse) ? NewLinePlacement.BeforeElse : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.NewLineForCatch) ? NewLinePlacement.BeforeCatch : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.NewLineForFinally) ? NewLinePlacement.BeforeFinally : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.NewLinesForBracesInTypes) ? NewLinePlacement.BeforeOpenBraceInTypes : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.NewLinesForBracesInAnonymousTypes) ? NewLinePlacement.BeforeOpenBraceInAnonymousTypes : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.NewLinesForBracesInObjectCollectionArrayInitializers) ? NewLinePlacement.BeforeOpenBraceInObjectCollectionArrayInitializers : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.NewLinesForBracesInProperties) ? NewLinePlacement.BeforeOpenBraceInProperties : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.NewLinesForBracesInMethods) ? NewLinePlacement.BeforeOpenBraceInMethods : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.NewLinesForBracesInAccessors) ? NewLinePlacement.BeforeOpenBraceInAccessors : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.NewLinesForBracesInAnonymousMethods) ? NewLinePlacement.BeforeOpenBraceInAnonymousMethods : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.NewLinesForBracesInLambdaExpressionBody) ? NewLinePlacement.BeforeOpenBraceInLambdaExpressionBody : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.NewLinesForBracesInControlBlocks) ? NewLinePlacement.BeforeOpenBraceInControlBlocks : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.NewLineForClausesInQuery) ? NewLinePlacement.BetweenQueryExpressionClauses : 0), - LabelPositioning = globalOptions.GetOption(CSharpFormattingOptions2.LabelPositioning), - Indentation = - (globalOptions.GetOption(CSharpFormattingOptions2.IndentBraces) ? IndentationPlacement.Braces : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.IndentBlock) ? IndentationPlacement.BlockContents : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.IndentSwitchCaseSection) ? IndentationPlacement.SwitchCaseContents : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.IndentSwitchCaseSectionWhenBlock) ? IndentationPlacement.SwitchCaseContentsWhenBlock : 0) | - (globalOptions.GetOption(CSharpFormattingOptions2.IndentSwitchSection) ? IndentationPlacement.SwitchSection : 0), - WrappingKeepStatementsOnSingleLine = globalOptions.GetOption(CSharpFormattingOptions2.WrappingKeepStatementsOnSingleLine), - WrappingPreserveSingleLine = globalOptions.GetOption(CSharpFormattingOptions2.WrappingPreserveSingleLine), - NamespaceDeclarations = globalOptions.GetOption(CSharpCodeStyleOptions.NamespaceDeclarations), - PreferTopLevelStatements = globalOptions.GetOption(CSharpCodeStyleOptions.PreferTopLevelStatements) - }; -} diff --git a/src/EditorFeatures/CSharp/Simplification/CSharpSimplifierOptionsStorage.cs b/src/EditorFeatures/CSharp/Simplification/CSharpSimplifierOptionsStorage.cs deleted file mode 100644 index e5dec6cf5fd97..0000000000000 --- a/src/EditorFeatures/CSharp/Simplification/CSharpSimplifierOptionsStorage.cs +++ /dev/null @@ -1,42 +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.Composition; -using Microsoft.CodeAnalysis.CodeStyle; -using Microsoft.CodeAnalysis.CSharp.CodeStyle; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Simplification; - -namespace Microsoft.CodeAnalysis.CSharp.Simplification; - -internal static class CSharpSimplifierOptionsStorage -{ - [ExportLanguageService(typeof(ISimplifierOptionsStorage), LanguageNames.CSharp), Shared] - internal sealed class Service : ISimplifierOptionsStorage - { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public Service() - { - } - - public SimplifierOptions GetOptions(IGlobalOptionService globalOptions) - => GetCSharpSimplifierOptions(globalOptions); - } - - public static CSharpSimplifierOptions GetCSharpSimplifierOptions(this IGlobalOptionService globalOptions) - => new() - { - Common = globalOptions.GetCommonSimplifierOptions(LanguageNames.CSharp), - VarForBuiltInTypes = globalOptions.GetOption(CSharpCodeStyleOptions.VarForBuiltInTypes), - VarWhenTypeIsApparent = globalOptions.GetOption(CSharpCodeStyleOptions.VarWhenTypeIsApparent), - VarElsewhere = globalOptions.GetOption(CSharpCodeStyleOptions.VarElsewhere), - PreferSimpleDefaultExpression = globalOptions.GetOption(CSharpCodeStyleOptions.PreferSimpleDefaultExpression), - AllowEmbeddedStatementsOnSameLine = globalOptions.GetOption(CSharpCodeStyleOptions.AllowEmbeddedStatementsOnSameLine), - PreferBraces = globalOptions.GetOption(CSharpCodeStyleOptions.PreferBraces), - PreferThrowExpression = globalOptions.GetOption(CSharpCodeStyleOptions.PreferThrowExpression), - }; -} diff --git a/src/EditorFeatures/CSharp/SplitStringLiteral/SplitStringLiteralCommandHandler.cs b/src/EditorFeatures/CSharp/SplitStringLiteral/SplitStringLiteralCommandHandler.cs index c5f53c6a64f8f..70ea5a59f4980 100644 --- a/src/EditorFeatures/CSharp/SplitStringLiteral/SplitStringLiteralCommandHandler.cs +++ b/src/EditorFeatures/CSharp/SplitStringLiteral/SplitStringLiteralCommandHandler.cs @@ -58,7 +58,7 @@ public bool ExecuteCommand(ReturnKeyCommandArgs args, CommandExecutionContext co public bool ExecuteCommandWorker(ReturnKeyCommandArgs args) { - if (!_editorOptionsService.GlobalOptions.GetOption(SplitStringLiteralOptions.Enabled, LanguageNames.CSharp)) + if (!_editorOptionsService.GlobalOptions.GetOption(SplitStringLiteralOptions.Enabled)) { return false; } diff --git a/src/EditorFeatures/CSharp/SplitStringLiteral/SplitStringLiteralOptions.cs b/src/EditorFeatures/CSharp/SplitStringLiteral/SplitStringLiteralOptions.cs index cb4a12bf858bb..50c97cb42af35 100644 --- a/src/EditorFeatures/CSharp/SplitStringLiteral/SplitStringLiteralOptions.cs +++ b/src/EditorFeatures/CSharp/SplitStringLiteral/SplitStringLiteralOptions.cs @@ -2,19 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Collections.Immutable; -using System.Composition; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Options.Providers; -namespace Microsoft.CodeAnalysis.Editor.CSharp.SplitStringLiteral +namespace Microsoft.CodeAnalysis.Editor.CSharp.SplitStringLiteral; + +internal sealed class SplitStringLiteralOptions { - internal sealed class SplitStringLiteralOptions - { - public static PerLanguageOption2 Enabled = - new(nameof(SplitStringLiteralOptions), nameof(Enabled), defaultValue: true, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.SplitStringLiterals")); - } + public static Option2 Enabled = new("SplitStringLiteralOptions_Enabled", defaultValue: true); } diff --git a/src/EditorFeatures/CSharpTest/AddUsing/AddUsingNuGetTests.cs b/src/EditorFeatures/CSharpTest/AddUsing/AddUsingNuGetTests.cs index 7e344a013b079..527c0ba53eed3 100644 --- a/src/EditorFeatures/CSharpTest/AddUsing/AddUsingNuGetTests.cs +++ b/src/EditorFeatures/CSharpTest/AddUsing/AddUsingNuGetTests.cs @@ -36,8 +36,8 @@ public class AddUsingNuGetTests : AbstractAddUsingTests protected override void InitializeWorkspace(TestWorkspace workspace, TestParameters parameters) { - workspace.GlobalOptions.SetGlobalOption(new OptionKey(SymbolSearchOptionsStorage.SearchNuGetPackages, LanguageNames.CSharp), true); - workspace.GlobalOptions.SetGlobalOption(new OptionKey(SymbolSearchOptionsStorage.SearchReferenceAssemblies, LanguageNames.CSharp), true); + workspace.GlobalOptions.SetGlobalOption(SymbolSearchOptionsStorage.SearchNuGetPackages, LanguageNames.CSharp, true); + workspace.GlobalOptions.SetGlobalOption(SymbolSearchOptionsStorage.SearchReferenceAssemblies, LanguageNames.CSharp, true); } internal override (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProviderAndFixer( diff --git a/src/EditorFeatures/CSharpTest/AutomaticCompletion/AutomaticBraceCompletionTests.cs b/src/EditorFeatures/CSharpTest/AutomaticCompletion/AutomaticBraceCompletionTests.cs index 51641b258431a..8923472f1d58d 100644 --- a/src/EditorFeatures/CSharpTest/AutomaticCompletion/AutomaticBraceCompletionTests.cs +++ b/src/EditorFeatures/CSharpTest/AutomaticCompletion/AutomaticBraceCompletionTests.cs @@ -787,7 +787,7 @@ public void man() }"; var globalOptions = new OptionsCollection(LanguageNames.CSharp) { - { CSharpFormattingOptions2.NewLinesForBracesInObjectCollectionArrayInitializers, false } + { CSharpFormattingOptions2.NewLineBeforeOpenBrace, CSharpFormattingOptions2.NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ObjectCollectionArrayInitializers, false) } }; using var session = CreateSession(code, globalOptions); @@ -863,7 +863,7 @@ class Goo }"; var globalOptions = new OptionsCollection(LanguageNames.CSharp) { - { CSharpFormattingOptions2.NewLinesForBracesInObjectCollectionArrayInitializers, false } + { CSharpFormattingOptions2.NewLineBeforeOpenBrace, CSharpFormattingOptions2.NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ObjectCollectionArrayInitializers, false) } }; using var session = CreateSession(code, globalOptions); @@ -935,7 +935,7 @@ public void man() }"; var globalOptions = new OptionsCollection(LanguageNames.CSharp) { - { CSharpFormattingOptions2.NewLinesForBracesInObjectCollectionArrayInitializers, false } + { CSharpFormattingOptions2.NewLineBeforeOpenBrace, CSharpFormattingOptions2.NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ObjectCollectionArrayInitializers, false) } }; using var session = CreateSession(code, globalOptions); @@ -997,7 +997,7 @@ public void man() }"; var globalOptions = new OptionsCollection(LanguageNames.CSharp) { - { CSharpFormattingOptions2.NewLinesForBracesInObjectCollectionArrayInitializers, false } + { CSharpFormattingOptions2.NewLineBeforeOpenBrace, CSharpFormattingOptions2.NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ObjectCollectionArrayInitializers, false) } }; using var session = CreateSession(code, globalOptions); @@ -1059,7 +1059,7 @@ public void man() }"; var globalOptions = new OptionsCollection(LanguageNames.CSharp) { - { CSharpFormattingOptions2.NewLinesForBracesInObjectCollectionArrayInitializers, false } + { CSharpFormattingOptions2.NewLineBeforeOpenBrace, CSharpFormattingOptions2.NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ObjectCollectionArrayInitializers, false) } }; using var session = CreateSession(code, globalOptions); Assert.NotNull(session); @@ -1384,7 +1384,7 @@ public void man(R r) }"; var globalOptions = new OptionsCollection(LanguageNames.CSharp) { - { CSharpFormattingOptions2.NewLinesForBracesInObjectCollectionArrayInitializers, bracesOnNewLine } + { CSharpFormattingOptions2.NewLineBeforeOpenBrace, CSharpFormattingOptions2.NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ObjectCollectionArrayInitializers, bracesOnNewLine) } }; using var session = CreateSession(code, globalOptions); Assert.NotNull(session); @@ -1428,7 +1428,7 @@ public void man() }"; var globalOptions = new OptionsCollection(LanguageNames.CSharp) { - { CSharpFormattingOptions2.NewLinesForBracesInObjectCollectionArrayInitializers, bracesOnNewLine } + { CSharpFormattingOptions2.NewLineBeforeOpenBrace, CSharpFormattingOptions2.NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ObjectCollectionArrayInitializers, bracesOnNewLine) } }; using var session = CreateSession(code, globalOptions); Assert.NotNull(session); @@ -1472,7 +1472,7 @@ public int I }"; var globalOptions = new OptionsCollection(LanguageNames.CSharp) { - { CSharpFormattingOptions2.NewLinesForBracesInAccessors, bracesOnNewLine } + { CSharpFormattingOptions2.NewLineBeforeOpenBrace, CSharpFormattingOptions2.NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.Accessors, bracesOnNewLine) } }; using var session = CreateSession(code, globalOptions); Assert.NotNull(session); @@ -1516,7 +1516,7 @@ public void man() }"; var globalOptions = new OptionsCollection(LanguageNames.CSharp) { - { CSharpFormattingOptions2.NewLinesForBracesInAnonymousMethods, bracesOnNewLine } + { CSharpFormattingOptions2.NewLineBeforeOpenBrace, CSharpFormattingOptions2.NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.AnonymousMethods, bracesOnNewLine) } }; using var session = CreateSession(code, globalOptions); Assert.NotNull(session); @@ -1560,7 +1560,7 @@ public void man() }"; var globalOptions = new OptionsCollection(LanguageNames.CSharp) { - { CSharpFormattingOptions2.NewLinesForBracesInAnonymousTypes, bracesOnNewLine } + { CSharpFormattingOptions2.NewLineBeforeOpenBrace, CSharpFormattingOptions2.NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.AnonymousTypes, bracesOnNewLine) } }; using var session = CreateSession(code, globalOptions); Assert.NotNull(session); @@ -1605,7 +1605,7 @@ public void man() var globalOptions = new OptionsCollection(LanguageNames.CSharp) { - { CSharpFormattingOptions2.NewLinesForBracesInControlBlocks, bracesOnNewLine } + { CSharpFormattingOptions2.NewLineBeforeOpenBrace, CSharpFormattingOptions2.NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ControlBlocks, bracesOnNewLine) } }; using var session = CreateSession(code, globalOptions); Assert.NotNull(session); @@ -1656,7 +1656,7 @@ public void man() var globalOptions = new OptionsCollection(LanguageNames.CSharp) { - { CSharpFormattingOptions2.NewLinesForBracesInControlBlocks, bracesOnNewLine } + { CSharpFormattingOptions2.NewLineBeforeOpenBrace, CSharpFormattingOptions2.NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ControlBlocks, bracesOnNewLine) } }; using var session = CreateSession(code, globalOptions); Assert.NotNull(session); diff --git a/src/EditorFeatures/CSharpTest/BlockCommentEditing/CloseBlockCommentTests.cs b/src/EditorFeatures/CSharpTest/BlockCommentEditing/CloseBlockCommentTests.cs index 2bfb574c1140d..931e28e391270 100644 --- a/src/EditorFeatures/CSharpTest/BlockCommentEditing/CloseBlockCommentTests.cs +++ b/src/EditorFeatures/CSharpTest/BlockCommentEditing/CloseBlockCommentTests.cs @@ -285,7 +285,7 @@ public void NotClosedAfterAsteriskSpaceWithOptionOff() Verify(code, expected, workspace => { var globalOptions = workspace.GetService(); - globalOptions.SetGlobalOption(new OptionKey(FeatureOnOffOptions.AutoInsertBlockCommentStartString, LanguageNames.CSharp), false); + globalOptions.SetGlobalOption(FeatureOnOffOptions.AutoInsertBlockCommentStartString, LanguageNames.CSharp, false); }); } diff --git a/src/EditorFeatures/CSharpTest/CodeActions/ConvertLinq/ConvertForEachToLinqQueryTests.cs b/src/EditorFeatures/CSharpTest/CodeActions/ConvertLinq/ConvertForEachToLinqQueryTests.cs index 12b94fd8d3922..cb3bc6b32d005 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/ConvertLinq/ConvertForEachToLinqQueryTests.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/ConvertLinq/ConvertForEachToLinqQueryTests.cs @@ -1872,7 +1872,7 @@ class C List M(IEnumerable nums) { List list0 = new List(); - return (nums.SelectMany(n1 => nums.Select(n2 => n1))).ToList(); + return nums.SelectMany(n1 => nums.Select(n2 => n1)).ToList(); } } "; @@ -2042,7 +2042,7 @@ class C { List M(IEnumerable nums) { - return (nums.SelectMany(n1 => nums.Select(n2 => n1))).ToList(); + return nums.SelectMany(n1 => nums.Select(n2 => n1)).ToList(); } } "; @@ -2155,7 +2155,7 @@ class C { List M(IEnumerable nums, List list) { - list = (nums.SelectMany(n1 => nums.Select(n2 => n1))).ToList(); + list = nums.SelectMany(n1 => nums.Select(n2 => n1)).ToList(); return list; } } @@ -2257,7 +2257,7 @@ class C { void M(IEnumerable nums, List[] lists) { - lists[0] = (nums.SelectMany(n1 => nums.Select(n2 => n1))).ToList(); + lists[0] = nums.SelectMany(n1 => nums.Select(n2 => n1)).ToList(); } } "; @@ -2331,7 +2331,7 @@ class C { List M(IEnumerable nums) { - return (nums.SelectMany(n1 => nums.Select(n2 => n1))).ToList(); + return nums.SelectMany(n1 => nums.Select(n2 => n1)).ToList(); } } "; @@ -2388,7 +2388,7 @@ class C List M(IEnumerable nums) { List list; - return (nums.SelectMany(n1 => nums.Select(n2 => n1))).ToList(); + return nums.SelectMany(n1 => nums.Select(n2 => n1)).ToList(); } } "; @@ -2445,7 +2445,7 @@ class C int M(IEnumerable nums) { List list; - list = (nums.SelectMany(n1 => nums.Select(n2 => n1))).ToList(); + list = nums.SelectMany(n1 => nums.Select(n2 => n1)).ToList(); return list.Count; } } @@ -2669,7 +2669,7 @@ public static void Main() { var nums = new int[] { 1, 2, 3, 4 }; var c = new C(); - c.A = (nums.Select(x => x + 1)).ToList(); + c.A = nums.Select(x => x + 1).ToList(); } class C @@ -2867,7 +2867,7 @@ class C { void M(IEnumerable nums) { - int i = 0, cnt = (nums.SelectMany(n1 => nums.Select(n2 => n1))).Count(); + int i = 0, cnt = nums.SelectMany(n1 => nums.Select(n2 => n1)).Count(); } } "; @@ -2921,7 +2921,7 @@ class C void M(IEnumerable nums) { int cnt = 0, i = 0; - cnt += (nums.SelectMany(n1 => nums.Select(n2 => n1))).Count(); + cnt += nums.SelectMany(n1 => nums.Select(n2 => n1)).Count(); } } "; @@ -2971,7 +2971,7 @@ class C { void M(IEnumerable nums, int c) { - c += (nums.SelectMany(n1 => nums.Select(n2 => n1))).Count(); + c += nums.SelectMany(n1 => nums.Select(n2 => n1)).Count(); } } "; @@ -3023,7 +3023,7 @@ class C { void M(IEnumerable nums, int c) { - c = (nums.SelectMany(n1 => nums.Select(n2 => n1))).Count(); + c = nums.SelectMany(n1 => nums.Select(n2 => n1)).Count(); } } "; @@ -3077,7 +3077,7 @@ class C void M(IEnumerable nums, int c) { c = 5; - c += (nums.SelectMany(n1 => nums.Select(n2 => n1))).Count(); + c += nums.SelectMany(n1 => nums.Select(n2 => n1)).Count(); } } "; @@ -3131,7 +3131,7 @@ class C { int M(IEnumerable nums) { - return (nums.SelectMany(n1 => nums.Select(n2 => n1))).Count(); + return nums.SelectMany(n1 => nums.Select(n2 => n1)).Count(); } } "; @@ -3185,7 +3185,7 @@ class C { double M(IEnumerable nums) { - return (nums.SelectMany(n1 => nums.Select(n2 => n1))).Count(); + return nums.SelectMany(n1 => nums.Select(n2 => n1)).Count(); } } "; @@ -3241,7 +3241,7 @@ class C int M(IEnumerable nums) { int c = 0; - return (nums.SelectMany(n1 => nums.Select(n2 => n1))).Count(); + return nums.SelectMany(n1 => nums.Select(n2 => n1)).Count(); } } "; @@ -3298,7 +3298,7 @@ class C int M(IEnumerable nums) { int c = 0, cnt = 5; - cnt += (nums.SelectMany(n1 => nums.Select(n2 => n1))).Count(); + cnt += nums.SelectMany(n1 => nums.Select(n2 => n1)).Count(); return cnt; } } @@ -3356,7 +3356,7 @@ class C int M(IEnumerable nums) { int cnt = 0, c = 0; - cnt += (nums.SelectMany(n1 => nums.Select(n2 => n1))).Count(); + cnt += nums.SelectMany(n1 => nums.Select(n2 => n1)).Count(); return cnt; } } @@ -3414,7 +3414,7 @@ class C int M(IEnumerable nums) { int cnt = 5, c = 0; - cnt += (nums.SelectMany(n1 => nums.Select(n2 => n1))).Count(); + cnt += nums.SelectMany(n1 => nums.Select(n2 => n1)).Count(); return cnt; } } @@ -3472,7 +3472,7 @@ class C int M(IEnumerable nums) { int cnt; - return (nums.SelectMany(n1 => nums.Select(n2 => n1))).Count(); + return nums.SelectMany(n1 => nums.Select(n2 => n1)).Count(); } } "; @@ -3532,7 +3532,7 @@ int M(IEnumerable nums) { int cnt; cnt = 5; - cnt += (nums.SelectMany(n1 => nums.Select(n2 => n1))).Count(); + cnt += nums.SelectMany(n1 => nums.Select(n2 => n1)).Count(); return cnt; } } @@ -3587,7 +3587,7 @@ class C { int M(IEnumerable nums, int c) { - c = (nums.SelectMany(n1 => nums.Select(n2 => n1))).Count(); + c = nums.SelectMany(n1 => nums.Select(n2 => n1)).Count(); return c; } } @@ -3642,7 +3642,7 @@ class C void M(IEnumerable nums) { var count = 5; - count += (nums.SelectMany(n1 => nums.Select(n2 => n1))).Count(); + count += nums.SelectMany(n1 => nums.Select(n2 => n1)).Count(); } } "; @@ -3697,7 +3697,7 @@ class C void M(IEnumerable nums) { int count = 1; - count = (nums.SelectMany(n1 => nums.Select(n2 => n1))).Count(); + count = nums.SelectMany(n1 => nums.Select(n2 => n1)).Count(); } } "; @@ -3754,7 +3754,7 @@ void M(IEnumerable nums) { var count = 0; count = 4; - count += (nums.SelectMany(n1 => nums.Select(n2 => n1))).Count(); + count += nums.SelectMany(n1 => nums.Select(n2 => n1)).Count(); } } "; @@ -3809,7 +3809,7 @@ class C { void M(IEnumerable nums, A a) { - a.B = (nums.SelectMany(n1 => nums.Select(n2 => n1))).Count(); + a.B = nums.SelectMany(n1 => nums.Select(n2 => n1)).Count(); } } "; @@ -3866,7 +3866,7 @@ class C void M(IEnumerable nums, A a) { a.B = 5; - a.B += (nums.SelectMany(n1 => nums.Select(n2 => n1))).Count(); + a.B += nums.SelectMany(n1 => nums.Select(n2 => n1)).Count(); } } "; @@ -3920,7 +3920,7 @@ class C { void M(IEnumerable nums, A a) { - a.B += (nums.SelectMany(n1 => nums.Select(n2 => n1))).Count(); + a.B += nums.SelectMany(n1 => nums.Select(n2 => n1)).Count(); } } "; @@ -3969,7 +3969,7 @@ class C { void M(IEnumerable nums) { - int c = (nums.AsQueryable()).Count(); + int c = nums.AsQueryable().Count(); } }"; @@ -4100,14 +4100,13 @@ List M(IEnumerable nums) { /*29*/ return /*30*/ /* 1 *//* 2 *//* 3 *//* 4 */// 5 -/*31*/ -( -/* 6 */from/* 8 *//* 7 *//* 9 */x /* 10 */ in/* 11 */nums/* 12 */// 13 + /*31*//* 6 */ + (from/* 8 *//* 7 *//* 9 */x /* 10 */ in/* 11 */nums/* 12 */// 13 /* 14 */// 15 /* 16 *//* 17 */ let y /* 18 */ = /* 19 */ x + 1/* 20 *///21 - select y/* 24 *//*27*///28 -).ToList()/* 22 *//* 23 *//* 25 *///26 + select y)/* 24 *//*27*///28 +.ToList()/* 22 *//* 23 *//* 25 *///26 ; //32 } }"; @@ -4147,12 +4146,11 @@ List M(IEnumerable nums) { /*23*/ return /*24*/ /* 1 *//* 2 *//* 3 *//* 4 */// 5 -/*25*/ -( -/* 14 */// 15 -/* 6 */from/* 8 *//* 7 *//* 9 */x /* 10 */ in/* 11 */nums/* 12 */// 13 - select x + 1/* 18 *//*21*///22 -).ToList()/* 16 *//* 17 *//* 19 *///20 + /*25*//* 14 */// 15 + /* 6 */ + (from/* 8 *//* 7 *//* 9 */x /* 10 */ in/* 11 */nums/* 12 */// 13 + select x + 1)/* 18 *//*21*///22 +.ToList()/* 16 *//* 17 *//* 19 *///20 ; //26 } }"; @@ -4168,12 +4166,11 @@ List M(IEnumerable nums) { /*23*/ return /*24*/ /* 1 *//* 2 *//* 3 *//* 4 */// 5 -/*25*/ -(nums /* 12 */.Select( +/*25*/nums /* 12 */.Select( /* 6 *//* 7 *//* 14 */// 15 /* 9 */x /* 10 */ => x + 1/* 18 *//*21*///22 /* 8 *//* 11 */// 13 -)).ToList()/* 16 *//* 17 *//* 19 *///20 +).ToList()/* 16 *//* 17 *//* 19 *///20 ; //26 } }"; @@ -4209,12 +4206,11 @@ int M(IEnumerable nums) { /*21*/ return /*22*/ /* 1 *//* 2 *//* 3 *//* 4 */// 5 -/*23*/ -( -/* 14 */// 15 -/* 6 */from/* 8 *//* 7 *//* 9 */x /* 10 */ in/* 11 */nums/* 12 */// 13 - select x/* 10 *//*19*///20 -).Count()/* 16 *//* 17 *///18 + /*23*//* 14 */// 15 + /* 6 */ + (from/* 8 *//* 7 *//* 9 */x /* 10 */ in/* 11 */nums/* 12 */// 13 + select x)/* 10 *//*19*///20 +.Count()/* 16 *//* 17 *///18 ; //24 } }"; @@ -4230,11 +4226,10 @@ int M(IEnumerable nums) { /*21*/ return /*22*/ /* 1 *//* 2 *//* 3 *//* 4 */// 5 -/*23*/ -(nums /* 12 *//* 6 *//* 7 *//* 14 */// 15 +/*23*/nums /* 12 *//* 6 *//* 7 *//* 14 */// 15 /* 9 *//* 10 *//* 10 *//*19*///20 /* 8 *//* 11 */// 13 -).Count()/* 16 *//* 17 *///18 +.Count()/* 16 *//* 17 *///18 ; //24 } }"; diff --git a/src/EditorFeatures/CSharpTest/CodeActions/EnableNullable/EnableNullableTests.cs b/src/EditorFeatures/CSharpTest/CodeActions/EnableNullable/EnableNullableTests.cs index f70e348a9707c..2d165b775dc31 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/EnableNullable/EnableNullableTests.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/EnableNullable/EnableNullableTests.cs @@ -521,7 +521,7 @@ class Example ExpectedDiagnostics = { // /0/Test3.cs(7,10): error CS8618: Non-nullable field 'value' must contain a non-null value when exiting constructor. Consider declaring the field as nullable. - DiagnosticResult.CompilerError("CS8618").WithLocation(0), + DiagnosticResult.CompilerError("CS8618").WithSpan("/0/Test3.cs", 7, 10, 7, 15).WithSpan("/0/Test3.cs", 7, 10, 7, 15).WithArguments("field", "value"), }, }, SolutionTransforms = { s_enableNullableInFixedSolution }, diff --git a/src/EditorFeatures/CSharpTest/CodeActions/ExtractMethod/ExtractMethodTests.cs b/src/EditorFeatures/CSharpTest/CodeActions/ExtractMethod/ExtractMethodTests.cs index 6471658d24a3b..c4fcb4fb66ae9 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/ExtractMethod/ExtractMethodTests.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/ExtractMethod/ExtractMethodTests.cs @@ -3410,7 +3410,7 @@ class C return x; } - private async Task NewMethod() + private async Task NewMethod() { return await DoSomethingAsync(); } @@ -4764,7 +4764,7 @@ private static int NewMethod(int y) } """); - [Fact(Skip = "https://github.com/dotnet/roslyn/issues/65221")] + [Fact] public Task ExtractMethod_InsideThisInitializer() => TestInRegularAndScript1Async( """ @@ -4788,7 +4788,7 @@ public C(int y) { } - private static NewMethod(int y) + private static int NewMethod(int y) { return y + 1; } diff --git a/src/EditorFeatures/CSharpTest/CompleteStatement/CSharpCompleteStatementCommandHandlerTests.cs b/src/EditorFeatures/CSharpTest/CompleteStatement/CSharpCompleteStatementCommandHandlerTests.cs index 6ac2dcb966888..2fe3cbd45b84d 100644 --- a/src/EditorFeatures/CSharpTest/CompleteStatement/CSharpCompleteStatementCommandHandlerTests.cs +++ b/src/EditorFeatures/CSharpTest/CompleteStatement/CSharpCompleteStatementCommandHandlerTests.cs @@ -4240,7 +4240,7 @@ public int XValue setOptionsOpt: workspace => { var globalOptions = workspace.GetService(); - globalOptions.SetGlobalOption(new OptionKey(FeatureOnOffOptions.AutomaticallyCompleteStatementOnSemicolon), false); + globalOptions.SetGlobalOption(FeatureOnOffOptions.AutomaticallyCompleteStatementOnSemicolon, false); }); } diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/LoadDirectiveCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/LoadDirectiveCompletionProviderTests.cs index ae5391dc6fad0..36ca14e0a5b58 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/LoadDirectiveCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/LoadDirectiveCompletionProviderTests.cs @@ -80,7 +80,7 @@ public void ShouldTriggerCompletion(string textWithPositionMarker, bool expected using var workspace = new TestWorkspace(composition: FeaturesTestCompositions.Features); var provider = workspace.ExportProvider.GetExports().Single(p => p.Metadata.Language == LanguageNames.CSharp && p.Metadata.Name == nameof(LoadDirectiveCompletionProvider)).Value; var languageServices = workspace.Services.GetLanguageServices(LanguageNames.CSharp); - Assert.Equal(expectedResult, provider.ShouldTriggerCompletion(languageServices.LanguageServices, SourceText.From(text), position, trigger: default, CompletionOptions.Default, OptionValueSet.Empty)); + Assert.Equal(expectedResult, provider.ShouldTriggerCompletion(languageServices.LanguageServices, SourceText.From(text), position, trigger: default, CompletionOptions.Default, OptionSet.Empty)); } } } diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ObjectCreationCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ObjectCreationCompletionProviderTests.cs index 6aa86b5bfef60..80dd756aaa0ae 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ObjectCreationCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ObjectCreationCompletionProviderTests.cs @@ -99,6 +99,23 @@ async Task M() await VerifyItemExistsAsync(markup, "FieldAccessException"); } + [Fact] + public async Task InAsyncMethodReturnValueTask() + { + var markup = +@"using System; +using System.Threading.Tasks; + +class Program +{ + async ValueTask<string> M2Async() + { + return new $$; + } +}"; + await VerifyItemExistsAsync(MakeMarkup(markup), "string"); + } + [Fact] public async Task IsCommitCharacterTest() { @@ -769,5 +786,18 @@ class Program }"; await VerifyProviderCommitAsync(markup, "List", expectedMark, commitChar: ';'); } + + private static string MakeMarkup(string source, string languageVersion = "Preview") + { + return $$""" + + + +{{source}} + + + +"""; + } } } diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/PartialMethodCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/PartialMethodCompletionProviderTests.cs index b44ab27d12f2d..cf6f2fadb3e96 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/PartialMethodCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/PartialMethodCompletionProviderTests.cs @@ -781,7 +781,7 @@ public async Task ExpressionBodyMethod() var workspace = workspaceFixture.Target.GetWorkspace(GetComposition()); workspace.GlobalOptions.SetGlobalOption( - new OptionKey(CSharpCodeStyleOptions.PreferExpressionBodiedMethods), + CSharpCodeStyleOptions.PreferExpressionBodiedMethods, new CodeStyleOption2(ExpressionBodyPreference.WhenPossible, NotificationOption2.Silent)); var text = @"using System; @@ -812,7 +812,7 @@ public async Task ExpressionBodyMethodExtended() var workspace = workspaceFixture.Target.GetWorkspace(GetComposition()); workspace.GlobalOptions.SetGlobalOption( - new OptionKey(CSharpCodeStyleOptions.PreferExpressionBodiedMethods), + CSharpCodeStyleOptions.PreferExpressionBodiedMethods, new CodeStyleOption2(ExpressionBodyPreference.WhenPossible, NotificationOption2.Silent)); var text = @"using System; diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ReferenceDirectiveCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ReferenceDirectiveCompletionProviderTests.cs index 1da0bb07f6c39..29293e5b106d5 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ReferenceDirectiveCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ReferenceDirectiveCompletionProviderTests.cs @@ -117,7 +117,7 @@ public void ShouldTriggerCompletion(string textWithPositionMarker, bool expected using var workspace = new TestWorkspace(composition: FeaturesTestCompositions.Features); var provider = workspace.ExportProvider.GetExports().Single(p => p.Metadata.Language == LanguageNames.CSharp && p.Metadata.Name == nameof(ReferenceDirectiveCompletionProvider)).Value; var languageServices = workspace.Services.GetLanguageServices(LanguageNames.CSharp); - Assert.Equal(expectedResult, provider.ShouldTriggerCompletion(languageServices.LanguageServices, SourceText.From(text), position, trigger: default, CompletionOptions.Default, OptionValueSet.Empty)); + Assert.Equal(expectedResult, provider.ShouldTriggerCompletion(languageServices.LanguageServices, SourceText.From(text), position, trigger: default, CompletionOptions.Default, OptionSet.Empty)); } } } diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests.cs index 236eac88b045a..c725f359fcd36 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests.cs @@ -6,7 +6,6 @@ using System; using System.Collections.Generic; -using System.Text; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Completion.Providers; using Microsoft.CodeAnalysis.CSharp; @@ -12021,6 +12020,14 @@ ref struct MyRefStruct { } await VerifyItemExistsAsync(MakeMarkup(source), "MyRefStruct"); } + [Fact] + public async Task NoSymbolCompletionsInEnumBaseList() + { + var source = "enum E : $$"; + + await VerifyNoItemsExistAsync(source); + } + private static string MakeMarkup(string source, string languageVersion = "Preview") { return $$""" diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests_NoInteractive.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests_NoInteractive.cs index dad3e5f510ac3..2f72384adc9d2 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests_NoInteractive.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests_NoInteractive.cs @@ -337,7 +337,7 @@ string Property var service = CompletionService.GetService(document); var options = CompletionOptions.Default; var displayOptions = SymbolDescriptionOptions.Default; - var completions = await service.GetCompletionsAsync(document, position, options, OptionValueSet.Empty); + var completions = await service.GetCompletionsAsync(document, position, options, OptionSet.Empty); var item = completions.ItemsList.First(i => i.DisplayText == "Beep"); var edit = testDocument.GetTextBuffer().CreateEdit(); diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionServiceTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionServiceTests.cs index 29432880c9997..cf3b94c5d7761 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionServiceTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionServiceTests.cs @@ -112,7 +112,7 @@ public async Task PassThroughOptions1() .AddDocument("TestDocument.cs", text); var service = CompletionService.GetService(document); - var options = new OptionValueSet(ImmutableDictionary.Empty.Add(new OptionKey(ThirdPartyOption.Instance, LanguageNames.CSharp), 1)); + var options = new TestOptionSet(ImmutableDictionary.Empty.Add(new OptionKey(ThirdPartyOption.Instance, LanguageNames.CSharp), 1)); service.ShouldTriggerCompletion(text, 1, CompletionTrigger.Invoke, options: options); #pragma warning disable RS0030 // Do not used banned APIs @@ -187,7 +187,7 @@ public class C1 // We want to make sure import completion providers are also participating. var options = CompletionOptions.Default with { ShowItemsFromUnimportedNamespaces = true }; - var completionList = await completionService.GetCompletionsAsync(document, position.Value, options, OptionValueSet.Empty); + var completionList = await completionService.GetCompletionsAsync(document, position.Value, options, OptionSet.Empty); // We expect completion to run on frozen partial semantic, which won't run source generator. Assert.Equal(0, generatorRanCount); diff --git a/src/EditorFeatures/CSharpTest/ConvertNamespace/ConvertNamespaceCommandHandlerTests.cs b/src/EditorFeatures/CSharpTest/ConvertNamespace/ConvertNamespaceCommandHandlerTests.cs index f475a3f686e5d..f70eaf4367484 100644 --- a/src/EditorFeatures/CSharpTest/ConvertNamespace/ConvertNamespaceCommandHandlerTests.cs +++ b/src/EditorFeatures/CSharpTest/ConvertNamespace/ConvertNamespaceCommandHandlerTests.cs @@ -85,7 +85,7 @@ class C } }"); - testState.Workspace.GlobalOptions.SetGlobalOption(new OptionKey(FeatureOnOffOptions.AutomaticallyCompleteStatementOnSemicolon), false); + testState.Workspace.GlobalOptions.SetGlobalOption(FeatureOnOffOptions.AutomaticallyCompleteStatementOnSemicolon, false); testState.SendTypeChar(';'); testState.AssertCodeIs( diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/RemoveAsyncModifier/RemoveAsyncModifierTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/RemoveAsyncModifier/RemoveAsyncModifierTests.cs index fd76513737fec..f26877ef0c11d 100644 --- a/src/EditorFeatures/CSharpTest/Diagnostics/RemoveAsyncModifier/RemoveAsyncModifierTests.cs +++ b/src/EditorFeatures/CSharpTest/Diagnostics/RemoveAsyncModifier/RemoveAsyncModifierTests.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.Threading.Tasks; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Testing; +using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics.RemoveAsyncModifier @@ -1032,6 +1031,34 @@ System.Threading.Tasks.Task Goo() }"); } + [Fact, WorkItem(65536, "https://github.com/dotnet/roslyn/issues/65536")] + public async Task Method_TaskOfT_BlockBody_QualifyTaskFromResultType() + { + await VerifyCS.VerifyCodeFixAsync(""" + using System.Threading.Tasks; + using System.Collections.Generic; + + class C + { + public async Task> {|CS1998:M|}() + { + return new int[0]; + } + } + """, """ + using System.Threading.Tasks; + using System.Collections.Generic; + + class C + { + public Task> M() + { + return Task.FromResult>(new int[0]); + } + } + """); + } + [Fact] public async Task IAsyncEnumerable_Missing() { diff --git a/src/EditorFeatures/CSharpTest/EditorConfigSettings/Updater/SettingsUpdaterTests.cs b/src/EditorFeatures/CSharpTest/EditorConfigSettings/Updater/SettingsUpdaterTests.cs index 53ec51825c1d5..f03a2ba41386d 100644 --- a/src/EditorFeatures/CSharpTest/EditorConfigSettings/Updater/SettingsUpdaterTests.cs +++ b/src/EditorFeatures/CSharpTest/EditorConfigSettings/Updater/SettingsUpdaterTests.cs @@ -45,6 +45,9 @@ private static Workspace CreateWorkspaceWithProjectAndDocuments() return workspace; } + private static IGlobalOptionService GetGlobalOptions(Workspace workspace) + => workspace.Services.SolutionServices.ExportProvider.GetExportedValue(); + private static AnalyzerConfigDocument CreateAnalyzerConfigDocument(Workspace workspace, string contents) { var solution = workspace.CurrentSolution; @@ -341,14 +344,15 @@ public async Task TestAnalyzerSettingsUpdaterService() public async Task TestCodeStyleSettingUpdaterService() { var workspace = CreateWorkspaceWithProjectAndDocuments(); + var globalOptions = GetGlobalOptions(workspace); + var updater = new OptionUpdater(workspace, EditorconfigPath); - var solution = workspace.CurrentSolution; var value = "false:silent"; var options = new TieredAnalyzerConfigOptions( new TestAnalyzerConfigOptions(key => value), - solution.Options.AsAnalyzerConfigOptions(solution.Services.GetRequiredService(), LanguageNames.CSharp), + globalOptions, LanguageNames.CSharp, EditorconfigPath); @@ -358,6 +362,8 @@ public async Task TestCodeStyleSettingUpdaterService() var update = Assert.Single(updates); Assert.Equal("[*.cs]\r\ncsharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = false:error", update.NewText); value = "false:error"; + + var solution = workspace.CurrentSolution; var editorconfig = solution.Projects.SelectMany(p => p.AnalyzerConfigDocuments.Where(a => a.FilePath == EditorconfigPath)).Single(); var text = await editorconfig.GetTextAsync(); @@ -374,12 +380,12 @@ public async Task TestCodeStyleSettingUpdaterService() public async Task TestWhitespaceSettingUpdaterService() { var workspace = CreateWorkspaceWithProjectAndDocuments(); + var globalOptions = GetGlobalOptions(workspace); var updater = new OptionUpdater(workspace, EditorconfigPath); - var solution = workspace.CurrentSolution; var options = new TieredAnalyzerConfigOptions( TestAnalyzerConfigOptions.Instance, - solution.Options.AsAnalyzerConfigOptions(solution.Services.GetRequiredService(), LanguageNames.CSharp), + globalOptions, LanguageNames.CSharp, EditorconfigPath); diff --git a/src/EditorFeatures/CSharpTest/EncapsulateField/EncapsulateFieldTestState.cs b/src/EditorFeatures/CSharpTest/EncapsulateField/EncapsulateFieldTestState.cs index 265554d58dc92..34650b34dd584 100644 --- a/src/EditorFeatures/CSharpTest/EncapsulateField/EncapsulateFieldTestState.cs +++ b/src/EditorFeatures/CSharpTest/EncapsulateField/EncapsulateFieldTestState.cs @@ -43,8 +43,8 @@ public static EncapsulateFieldTestState Create(string markup) { var workspace = TestWorkspace.CreateCSharp(markup, composition: EditorTestCompositions.EditorFeatures); - workspace.GlobalOptions.SetGlobalOption(new OptionKey(CSharpCodeStyleOptions.PreferExpressionBodiedAccessors), CSharpCodeStyleOptions.NeverWithSilentEnforcement); - workspace.GlobalOptions.SetGlobalOption(new OptionKey(CSharpCodeStyleOptions.PreferExpressionBodiedProperties), CSharpCodeStyleOptions.NeverWithSilentEnforcement); + workspace.GlobalOptions.SetGlobalOption(CSharpCodeStyleOptions.PreferExpressionBodiedAccessors, CSharpCodeStyleOptions.NeverWithSilentEnforcement); + workspace.GlobalOptions.SetGlobalOption(CSharpCodeStyleOptions.PreferExpressionBodiedProperties, CSharpCodeStyleOptions.NeverWithSilentEnforcement); return new EncapsulateFieldTestState(workspace); } diff --git a/src/EditorFeatures/CSharpTest/ExtractClass/ExtractClassTests.cs b/src/EditorFeatures/CSharpTest/ExtractClass/ExtractClassTests.cs index b1711ecde186a..794f7698a3390 100644 --- a/src/EditorFeatures/CSharpTest/ExtractClass/ExtractClassTests.cs +++ b/src/EditorFeatures/CSharpTest/ExtractClass/ExtractClassTests.cs @@ -2521,6 +2521,133 @@ public void $$N }.RunAsync(); } + [Fact] + [WorkItem(55610, "https://github.com/dotnet/roslyn/issues/55610")] + public async Task TestMultipleMethodsSelected_WithTypeContainingBaseClass() + { + var code = """ + class Base + { + } + + class Derived : Base + { + [|public void M() { } + public void N() { }|] + } + """; + + await new Test() + { + TestCode = code, + FixedCode = code + }.RunAsync(); + } + + [Fact] + [WorkItem(55610, "https://github.com/dotnet/roslyn/issues/55610")] + public async Task TestClassSelected_WithTypeContainingBaseClass() + { + var code = """ + class Base + { + } + + class $$Derived : Base + { + public void M() { } + public void N() { } + } + """; + + await new Test() + { + TestCode = code, + FixedCode = code + }.RunAsync(); + } + + [Fact] + public async Task TestMultipleMethodsSelected_HighlightedMembersAreSelected() + { + var code = """ + class C + { + [|public void M() { } + public void N() { }|] + public void O() { } + } + """; + + var expected1 = """ + class C : MyBase + { + public void O() { } + } + """; + + var expected2 = """ + internal class MyBase + { + public void M() { } + public void N() { } + } + """; + + await new Test() + { + TestCode = code, + FixedState = + { + Sources = + { + expected1, + expected2 + } + }, + FileName = "Test1.cs" + }.RunAsync(); + } + + [Fact] + [WorkItem(55402, "https://github.com/dotnet/roslyn/issues/55402")] + public async Task TestMemberKeyword() + { + var code = """ + class C + { + $$public void M() { } + } + """; + + var expected1 = """ + class C : MyBase + { + } + """; + + var expected2 = """ + internal class MyBase + { + public void M() { } + } + """; + + await new Test + { + TestCode = code, + FixedState = + { + Sources = + { + expected1, + expected2 + } + }, + FileName = "Test1.cs", + }.RunAsync(); + } + private static IEnumerable<(string name, bool makeAbstract)> MakeAbstractSelection(params string[] memberNames) => memberNames.Select(m => (m, true)); @@ -2531,13 +2658,13 @@ private class TestExtractClassOptionsService : IExtractClassOptionsService { private readonly IEnumerable<(string name, bool makeAbstract)>? _dialogSelection; private readonly bool _sameFile; - private readonly bool isClassDeclarationSelection; + private readonly bool _isClassDeclarationSelection; public TestExtractClassOptionsService(IEnumerable<(string name, bool makeAbstract)>? dialogSelection = null, bool sameFile = false, bool isClassDeclarationSelection = false) { _dialogSelection = dialogSelection; _sameFile = sameFile; - this.isClassDeclarationSelection = isClassDeclarationSelection; + _isClassDeclarationSelection = isClassDeclarationSelection; } public string FileName { get; set; } = "MyBase.cs"; @@ -2553,12 +2680,12 @@ public TestExtractClassOptionsService(IEnumerable<(string name, bool makeAbstrac { if (selectedMembers.IsEmpty) { - Assert.True(isClassDeclarationSelection); + Assert.True(_isClassDeclarationSelection); selections = availableMembers.Select(member => (member, makeAbstract: false)); } else { - Assert.False(isClassDeclarationSelection); + Assert.False(_isClassDeclarationSelection); selections = selectedMembers.Select(m => (m, makeAbstract: false)); } } diff --git a/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.LanguageInteraction.cs b/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.LanguageInteraction.cs index 81f113ac23653..d461fd594fa6f 100644 --- a/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.LanguageInteraction.cs +++ b/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.LanguageInteraction.cs @@ -2012,5 +2012,61 @@ private static void NewMethod(C c) await TestExtractMethodAsync(code, expected); } + + [Fact, WorkItem(39329, "https://github.com/dotnet/roslyn/issues/39329")] + public Task SimpleUsingStatement() + { + var code = """ + public class Goo : IDisposable + { + void M2() { } + void M3() { } + string S => "S"; + + void M() + { + using Goo g = [|new Goo(); + var s = g.S; + g.M2(); + g.M3();|] + } + + public void Dispose() + { + throw new NotImplementedException(); + } + } + """; + + var expected = """ + public class Goo : IDisposable + { + void M2() { } + void M3() { } + string S => "S"; + + void M() + { + using Goo g = NewMethod(); + } + + private static Goo NewMethod() + { + Goo g = new Goo(); + var s = g.S; + g.M2(); + g.M3(); + return g; + } + + public void Dispose() + { + throw new NotImplementedException(); + } + } + """; + + return TestExtractMethodAsync(code, expected); + } } } diff --git a/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.cs b/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.cs index 09d1d85ad7d4b..5ed87c0b307cb 100644 --- a/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.cs +++ b/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.cs @@ -8915,6 +8915,42 @@ private static int GetY(S x) await TestExtractMethodAsync(code, expected); } + [Fact] + public async Task NullabilityTypeParameters() + { + var code = @" +#nullable enable + +using System.Collections.Generic; + +public class Test +{ + public int M(Dictionary v) + { + [|return v.Count;|] + } +}"; + var expected = @" +#nullable enable + +using System.Collections.Generic; + +public class Test +{ + public int M(Dictionary v) + { + return NewMethod(v); + } + + private static int NewMethod(Dictionary v) + { + return v.Count; + } +}"; + + await TestExtractMethodAsync(code, expected); + } + [Fact, WorkItem(543012, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543012")] public async Task TypeParametersInConstraintBestEffort() { diff --git a/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs b/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs index 1627fcd262374..01c7d93117042 100644 --- a/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs +++ b/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs @@ -816,9 +816,9 @@ private protected static async Task AssertCodeCleanupResult(string expected, str // must set global options since incremental analyzer infra reads from global options var globalOptions = workspace.GlobalOptions; - globalOptions.SetGlobalOption(new OptionKey(GenerationOptions.SeparateImportDirectiveGroups, LanguageNames.CSharp), separateUsingGroups); - globalOptions.SetGlobalOption(new OptionKey(GenerationOptions.PlaceSystemNamespaceFirst, LanguageNames.CSharp), systemUsingsFirst); - globalOptions.SetGlobalOption(new OptionKey(CSharpCodeStyleOptions.PreferredUsingDirectivePlacement), preferredImportPlacement); + globalOptions.SetGlobalOption(GenerationOptions.SeparateImportDirectiveGroups, LanguageNames.CSharp, separateUsingGroups); + globalOptions.SetGlobalOption(GenerationOptions.PlaceSystemNamespaceFirst, LanguageNames.CSharp, systemUsingsFirst); + globalOptions.SetGlobalOption(CSharpCodeStyleOptions.PreferredUsingDirectivePlacement, preferredImportPlacement); var solution = workspace.CurrentSolution.WithAnalyzerReferences(new[] { diff --git a/src/EditorFeatures/CSharpTest/Formatting/RazorLineFormattingOptionsTests.cs b/src/EditorFeatures/CSharpTest/Formatting/RazorLineFormattingOptionsTests.cs index cd5f5e8c6ef8c..1e317dc4b7e04 100644 --- a/src/EditorFeatures/CSharpTest/Formatting/RazorLineFormattingOptionsTests.cs +++ b/src/EditorFeatures/CSharpTest/Formatting/RazorLineFormattingOptionsTests.cs @@ -41,8 +41,8 @@ public async Task FormatAsync() using var workspace = new AdhocWorkspace(hostServices); var globalOptions = ((IMefHostExportProvider)hostServices).GetExportedValue(); - globalOptions.SetGlobalOption(new OptionKey(RazorLineFormattingOptionsStorage.UseTabs), true); - globalOptions.SetGlobalOption(new OptionKey(RazorLineFormattingOptionsStorage.TabSize), 10); + globalOptions.SetGlobalOption(RazorLineFormattingOptionsStorage.UseTabs, true); + globalOptions.SetGlobalOption(RazorLineFormattingOptionsStorage.TabSize, 10); var project = workspace.AddProject("Test", LanguageNames.CSharp); diff --git a/src/EditorFeatures/CSharpTest/InlineDiagnostics/InlineDiagnosticsTaggerProviderTests.cs b/src/EditorFeatures/CSharpTest/InlineDiagnostics/InlineDiagnosticsTaggerProviderTests.cs index 0b7921bae4d60..0f5a23e5520e4 100644 --- a/src/EditorFeatures/CSharpTest/InlineDiagnostics/InlineDiagnosticsTaggerProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/InlineDiagnostics/InlineDiagnosticsTaggerProviderTests.cs @@ -57,7 +57,7 @@ private static async Task>> GetTag private static async Task>> GetTagSpansAsync(TestWorkspace workspace) { - workspace.GlobalOptions.SetGlobalOption(new OptionKey(InlineDiagnosticsOptions.EnableInlineDiagnostics, LanguageNames.CSharp), true); + workspace.GlobalOptions.SetGlobalOption(InlineDiagnosticsOptions.EnableInlineDiagnostics, LanguageNames.CSharp, true); return (await TestDiagnosticTagProducer.GetDiagnosticsAndErrorSpans(workspace)).Item2; } } diff --git a/src/EditorFeatures/CSharpTest/PullMemberUp/CSharpPullMemberUpTests.cs b/src/EditorFeatures/CSharpTest/PullMemberUp/CSharpPullMemberUpTests.cs index 7e52eb7be018f..e5250e0259428 100644 --- a/src/EditorFeatures/CSharpTest/PullMemberUp/CSharpPullMemberUpTests.cs +++ b/src/EditorFeatures/CSharpTest/PullMemberUp/CSharpPullMemberUpTests.cs @@ -4214,6 +4214,34 @@ public class Bar : BaseClass return TestWithPullMemberDialogAsync(text, expected); } + [Fact, WorkItem(55402, "https://github.com/dotnet/roslyn/issues/55402")] + public Task TestPullPropertyToClassOnKeyword() + { + var text = """ + public class BaseClass + { + } + + public class Derived : BaseClass + { + $$public int I => 1; + } + """; + + var expected = """ + public class BaseClass + { + $$public int I => 1; + } + + public class Derived : BaseClass + { + } + """; + + return TestWithPullMemberDialogAsync(text, expected); + } + #endregion Quick Action #region Dialog diff --git a/src/EditorFeatures/CSharpTest/SplitStringLiteral/SplitStringLiteralCommandHandlerTests.cs b/src/EditorFeatures/CSharpTest/SplitStringLiteral/SplitStringLiteralCommandHandlerTests.cs index 6d0f14c70e24d..f8a64853b53ac 100644 --- a/src/EditorFeatures/CSharpTest/SplitStringLiteral/SplitStringLiteralCommandHandlerTests.cs +++ b/src/EditorFeatures/CSharpTest/SplitStringLiteral/SplitStringLiteralCommandHandlerTests.cs @@ -67,7 +67,7 @@ private static void TestWorker( options.SetOptionValue(DefaultOptions.IndentStyleId, indentStyle.ToEditorIndentStyle()); // Remove once https://github.com/dotnet/roslyn/issues/62204 is fixed: - workspace.GlobalOptions.SetGlobalOption(new OptionKey(IndentationOptionsStorage.SmartIndent, document.Project.Language), indentStyle); + workspace.GlobalOptions.SetGlobalOption(IndentationOptionsStorage.SmartIndent, document.Project.Language, indentStyle); var originalSnapshot = textBuffer.CurrentSnapshot; var originalSelections = document.SelectedSpans; diff --git a/src/EditorFeatures/CSharpTest/Squiggles/ErrorSquiggleProducerTests.cs b/src/EditorFeatures/CSharpTest/Squiggles/ErrorSquiggleProducerTests.cs index fb45cf7efa924..2c35211e39d15 100644 --- a/src/EditorFeatures/CSharpTest/Squiggles/ErrorSquiggleProducerTests.cs +++ b/src/EditorFeatures/CSharpTest/Squiggles/ErrorSquiggleProducerTests.cs @@ -81,8 +81,7 @@ void Test() "; using var workspace = TestWorkspace.Create(workspaceXml); - workspace.GlobalOptions.SetGlobalOption( - new OptionKey(DiagnosticTaggingOptions.PullDiagnosticTagging), pull); + workspace.GlobalOptions.SetGlobalOption(DiagnosticTaggingOptions.PullDiagnosticTagging, pull); var spans = (await TestDiagnosticTagProducer.GetDiagnosticsAndErrorSpans(workspace)).Item2; @@ -118,11 +117,10 @@ void Test() using var workspace = TestWorkspace.Create(workspaceXml, composition: SquiggleUtilities.CompositionWithSolutionCrawler); var language = workspace.Projects.Single().Language; - workspace.GlobalOptions.SetGlobalOption( - new OptionKey(DiagnosticTaggingOptions.PullDiagnosticTagging), pull); + workspace.GlobalOptions.SetGlobalOption(DiagnosticTaggingOptions.PullDiagnosticTagging, pull); workspace.GlobalOptions.SetGlobalOption( - new OptionKey(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration, language), + CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration, language, new CodeStyleOption2(value: true, notification: NotificationOption2.Error)); var analyzerMap = new Dictionary> @@ -214,8 +212,7 @@ public async Task SemanticErrorReported(bool pull) { using var workspace = TestWorkspace.CreateCSharp("class C : Bar { }", composition: SquiggleUtilities.CompositionWithSolutionCrawler); - workspace.GlobalOptions.SetGlobalOption( - new OptionKey(DiagnosticTaggingOptions.PullDiagnosticTagging), pull); + workspace.GlobalOptions.SetGlobalOption(DiagnosticTaggingOptions.PullDiagnosticTagging, pull); var spans = await TestDiagnosticTagProducer.GetDiagnosticsAndErrorSpans(workspace); @@ -240,8 +237,7 @@ public async Task SemanticErrorReported(bool pull) public async Task TestNoErrorsAfterDocumentRemoved(bool pull) { using var workspace = TestWorkspace.CreateCSharp("class"); - workspace.GlobalOptions.SetGlobalOption( - new OptionKey(DiagnosticTaggingOptions.PullDiagnosticTagging), pull); + workspace.GlobalOptions.SetGlobalOption(DiagnosticTaggingOptions.PullDiagnosticTagging, pull); using var wrapper = new DiagnosticTaggerWrapper(workspace); @@ -271,8 +267,7 @@ public async Task TestNoErrorsAfterDocumentRemoved(bool pull) public async Task TestNoErrorsAfterProjectRemoved(bool pull) { using var workspace = TestWorkspace.CreateCSharp("class"); - workspace.GlobalOptions.SetGlobalOption( - new OptionKey(DiagnosticTaggingOptions.PullDiagnosticTagging), pull); + workspace.GlobalOptions.SetGlobalOption(DiagnosticTaggingOptions.PullDiagnosticTagging, pull); using var wrapper = new DiagnosticTaggerWrapper(workspace); @@ -318,8 +313,7 @@ class Test "; using var workspace = TestWorkspace.Create(workspaceXml, composition: s_mockComposition); - workspace.GlobalOptions.SetGlobalOption( - new OptionKey(DiagnosticTaggingOptions.PullDiagnosticTagging), pull); + workspace.GlobalOptions.SetGlobalOption(DiagnosticTaggingOptions.PullDiagnosticTagging, pull); var document = workspace.Documents.First(); @@ -363,8 +357,7 @@ class Test "; using var workspace = TestWorkspace.Create(workspaceXml, composition: s_mockComposition); - workspace.GlobalOptions.SetGlobalOption( - new OptionKey(DiagnosticTaggingOptions.PullDiagnosticTagging), pull); + workspace.GlobalOptions.SetGlobalOption(DiagnosticTaggingOptions.PullDiagnosticTagging, pull); var document = workspace.Documents.First(); @@ -408,8 +401,7 @@ private static async Task>> GetTagSpansInSour private static async Task>> GetTagSpansAsync(TestWorkspace workspace, bool pull) { - workspace.GlobalOptions.SetGlobalOption( - new OptionKey(DiagnosticTaggingOptions.PullDiagnosticTagging), pull); + workspace.GlobalOptions.SetGlobalOption(DiagnosticTaggingOptions.PullDiagnosticTagging, pull); return (await TestDiagnosticTagProducer.GetDiagnosticsAndErrorSpans(workspace)).Item2; } diff --git a/src/EditorFeatures/CSharpTest/SuggestionTags/SuggestionTagProducerTests.cs b/src/EditorFeatures/CSharpTest/SuggestionTags/SuggestionTagProducerTests.cs index 2fba35f95ec46..3612562abf6de 100644 --- a/src/EditorFeatures/CSharpTest/SuggestionTags/SuggestionTagProducerTests.cs +++ b/src/EditorFeatures/CSharpTest/SuggestionTags/SuggestionTagProducerTests.cs @@ -44,8 +44,7 @@ void M() { string content, bool pull) { using var workspace = TestWorkspace.CreateCSharp(content); - workspace.GlobalOptions.SetGlobalOption( - new OptionKey(DiagnosticTaggingOptions.PullDiagnosticTagging), pull); + workspace.GlobalOptions.SetGlobalOption(DiagnosticTaggingOptions.PullDiagnosticTagging, pull); var analyzerMap = new Dictionary>() { diff --git a/src/EditorFeatures/CSharpTest/TaskList/NoCompilationTaskListTests.cs b/src/EditorFeatures/CSharpTest/TaskList/NoCompilationTaskListTests.cs index 642ae2ad6d356..0b1b4de39fb6b 100644 --- a/src/EditorFeatures/CSharpTest/TaskList/NoCompilationTaskListTests.cs +++ b/src/EditorFeatures/CSharpTest/TaskList/NoCompilationTaskListTests.cs @@ -64,7 +64,7 @@ public Task> GetTaskListItemsAsync(Document documen descriptors.First().Priority, "Message", document.Id, - span: new FileLinePositionSpan("dummy", new LinePosition(0, 3), new LinePosition(0, 3)), - mappedSpan: new FileLinePositionSpan("dummy", new LinePosition(0, 3), new LinePosition(0, 3))))); + Span: new FileLinePositionSpan("dummy", new LinePosition(0, 3), new LinePosition(0, 3)), + MappedSpan: new FileLinePositionSpan("dummy", new LinePosition(0, 3), new LinePosition(0, 3))))); } } diff --git a/src/EditorFeatures/CSharpTest/Workspaces/WorkspaceTests_EditorFeatures.cs b/src/EditorFeatures/CSharpTest/Workspaces/WorkspaceTests_EditorFeatures.cs index 6513a6bedeabd..73464533e726e 100644 --- a/src/EditorFeatures/CSharpTest/Workspaces/WorkspaceTests_EditorFeatures.cs +++ b/src/EditorFeatures/CSharpTest/Workspaces/WorkspaceTests_EditorFeatures.cs @@ -1391,7 +1391,7 @@ public void TestSolutionWithOptions() using var workspace1 = CreateWorkspace(); var solution = workspace1.CurrentSolution; - var optionKey = new OptionKey2(FormattingOptions2.SmartIndent, LanguageNames.CSharp); + var optionKey = new OptionKey(FormattingOptions2.SmartIndent, LanguageNames.CSharp); var defaultValue = solution.Options.GetOption(optionKey); var changedValue = FormattingOptions.IndentStyle.Block; Assert.NotEqual(defaultValue, changedValue); @@ -1429,7 +1429,7 @@ public void TestOptionChangedHandlerInvokedAfterCurrentSolutionChanged() var beforeSolutionForPrimaryWorkspace = primaryWorkspace.CurrentSolution; var beforeSolutionForSecondaryWorkspace = secondaryWorkspace.CurrentSolution; - var optionKey = new OptionKey2(FormattingOptions2.SmartIndent, LanguageNames.CSharp); + var optionKey = new OptionKey(FormattingOptions2.SmartIndent, LanguageNames.CSharp); Assert.Equal(FormattingOptions2.IndentStyle.Smart, primaryWorkspace.Options.GetOption(optionKey)); Assert.Equal(FormattingOptions2.IndentStyle.Smart, secondaryWorkspace.Options.GetOption(optionKey)); @@ -1440,29 +1440,24 @@ public void TestOptionChangedHandlerInvokedAfterCurrentSolutionChanged() primaryWorkspace.Options = primaryWorkspace.Options.WithChangedOption(optionKey, FormattingOptions2.IndentStyle.Block); // Verify current solution and option change for both workspaces. - VerifyCurrentSolutionAndOptionChange(primaryWorkspace, beforeSolutionForPrimaryWorkspace); - VerifyCurrentSolutionAndOptionChange(secondaryWorkspace, beforeSolutionForSecondaryWorkspace); + Assert.NotEqual(beforeSolutionForPrimaryWorkspace, primaryWorkspace.CurrentSolution); + Assert.NotEqual(beforeSolutionForSecondaryWorkspace, secondaryWorkspace.CurrentSolution); + + Assert.Equal(FormattingOptions2.IndentStyle.Block, primaryWorkspace.Options.GetOption(optionKey)); + Assert.Equal(FormattingOptions2.IndentStyle.Block, secondaryWorkspace.Options.GetOption(optionKey)); primaryWorkspace.GlobalOptions.OptionChanged -= OptionService_OptionChanged; return; void OptionService_OptionChanged(object sender, OptionChangedEventArgs e) { - // Verify current solution and option change for both workspaces. - VerifyCurrentSolutionAndOptionChange(primaryWorkspace, beforeSolutionForPrimaryWorkspace); - VerifyCurrentSolutionAndOptionChange(secondaryWorkspace, beforeSolutionForSecondaryWorkspace); - } + // CurrentSolution has been updated when the event fires. - static void VerifyCurrentSolutionAndOptionChange(Workspace workspace, Solution beforeOptionChangedSolution) - { - // Verify that workspace.CurrentSolution has been updated with a new solution instance with changed option. - var currentSolution = workspace.CurrentSolution; - Assert.NotEqual(beforeOptionChangedSolution, currentSolution); - - // Verify workspace.CurrentSolution has changed option. - var optionKey = new OptionKey2(FormattingOptions2.SmartIndent, LanguageNames.CSharp); - Assert.Equal(FormattingOptions2.IndentStyle.Smart, beforeOptionChangedSolution.Options.GetOption(optionKey)); - Assert.Equal(FormattingOptions2.IndentStyle.Block, currentSolution.Options.GetOption(optionKey)); + Assert.NotSame(beforeSolutionForPrimaryWorkspace, primaryWorkspace.CurrentSolution); + Assert.NotSame(beforeSolutionForSecondaryWorkspace, secondaryWorkspace.CurrentSolution); + + Assert.Equal(FormattingOptions2.IndentStyle.Block, primaryWorkspace.Options.GetOption(optionKey)); + Assert.Equal(FormattingOptions2.IndentStyle.Block, secondaryWorkspace.Options.GetOption(optionKey)); } } } diff --git a/src/EditorFeatures/CSharpTest2/EmbeddedLanguages/Json/CSharpJsonParserTests.cs b/src/EditorFeatures/CSharpTest2/EmbeddedLanguages/Json/CSharpJsonParserTests.cs index 4bb2029c6c173..8eaeccc17a944 100644 --- a/src/EditorFeatures/CSharpTest2/EmbeddedLanguages/Json/CSharpJsonParserTests.cs +++ b/src/EditorFeatures/CSharpTest2/EmbeddedLanguages/Json/CSharpJsonParserTests.cs @@ -13,6 +13,7 @@ using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; using Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json; using Newtonsoft.Json.Linq; +using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.EmbeddedLanguages.Json @@ -388,7 +389,7 @@ private object RemoveSequenceNode(XNode node) } [Fact] - public void TestDeepRecursion() + public void TestDeepRecursion1() { var (token, tree, chars) = JustParseTree( @@ -430,6 +431,55 @@ public void TestDeepRecursion() [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[""", +JsonOptions.Loose, conversionFailureOk: false); + Assert.False(token.IsMissing); + Assert.False(chars.IsDefaultOrEmpty); + Assert.Null(tree); + } + + [Fact, WorkItem(1691963, "https://devdiv.visualstudio.com/DevDiv/_queries/edit/1691963")] + public void TestDeepRecursion2() + { + var (token, tree, chars) = + JustParseTree( +@"@"":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::""", JsonOptions.Loose, conversionFailureOk: false); Assert.False(token.IsMissing); Assert.False(chars.IsDefaultOrEmpty); diff --git a/src/EditorFeatures/CSharpTest2/EmbeddedLanguages/Json/CSharpJsonParserTests_BasicTests.cs b/src/EditorFeatures/CSharpTest2/EmbeddedLanguages/Json/CSharpJsonParserTests_BasicTests.cs index 350f9bdec9ddd..5ca1921ed8e53 100644 --- a/src/EditorFeatures/CSharpTest2/EmbeddedLanguages/Json/CSharpJsonParserTests_BasicTests.cs +++ b/src/EditorFeatures/CSharpTest2/EmbeddedLanguages/Json/CSharpJsonParserTests_BasicTests.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 Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.EmbeddedLanguages.Json @@ -5928,6 +5929,43 @@ public void TestColonPropertyName() ", @" +"); + } + + [Fact, WorkItem(1691963, "https://devdiv.visualstudio.com/DevDiv/_queries/edit/1691963")] + public void TestAllColons_BecomesNestedProperties() + { + Test(@"""::::::::""", expected: @" + + + + : + : + + : + : + + : + : + + : + : + + + + + + + + + + +", + @" + +", + @" + "); } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/DelegateKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/DelegateKeywordRecommenderTests.cs index 00e115cfd1417..2cde666183ac0 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/DelegateKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/DelegateKeywordRecommenderTests.cs @@ -429,5 +429,11 @@ class C { delegate*<$$"); } + + [Fact] + public async Task TestNotInEnumBaseList() + { + await VerifyAbsenceAsync("enum E : $$"); + } } } diff --git a/src/EditorFeatures/Core.Wpf/InlineDiagnostics/InlineDiagnosticsTaggerProvider.cs b/src/EditorFeatures/Core.Wpf/InlineDiagnostics/InlineDiagnosticsTaggerProvider.cs index 9b8d2722e749d..292d5848de957 100644 --- a/src/EditorFeatures/Core.Wpf/InlineDiagnostics/InlineDiagnosticsTaggerProvider.cs +++ b/src/EditorFeatures/Core.Wpf/InlineDiagnostics/InlineDiagnosticsTaggerProvider.cs @@ -35,8 +35,8 @@ internal sealed class InlineDiagnosticsTaggerProvider : AbstractDiagnosticsAdorn private readonly IClassificationFormatMapService _classificationFormatMapService; private readonly IClassificationTypeRegistryService _classificationTypeRegistryService; - protected sealed override ImmutableArray Options { get; } = ImmutableArray.Create(InlineDiagnosticsOptions.EnableInlineDiagnostics); - protected sealed override ImmutableArray FeatureOptions { get; } = ImmutableArray.Create(InlineDiagnosticsOptions.Location); + protected sealed override ImmutableArray Options { get; } = ImmutableArray.Create(InlineDiagnosticsOptions.EnableInlineDiagnostics); + protected sealed override ImmutableArray FeatureOptions { get; } = ImmutableArray.Create(InlineDiagnosticsOptions.Location); [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] diff --git a/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsKeyProcessorProvider.cs b/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsKeyProcessorProvider.cs index 6829d8a1c7a21..23cffcfdf0fc2 100644 --- a/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsKeyProcessorProvider.cs +++ b/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsKeyProcessorProvider.cs @@ -116,7 +116,7 @@ private void Toggle(bool on) // We can only enter the on-state if the user has the chord feature enabled. We can always enter the // off state though. on = on && _globalOptions.GetOption(InlineHintsViewOptions.DisplayAllHintsWhilePressingAltF1); - _globalOptions.RefreshOption(new OptionKey(InlineHintsGlobalStateOption.DisplayAllOverride), on); + _globalOptions.RefreshOption(new OptionKey2(InlineHintsGlobalStateOption.DisplayAllOverride), on); } } } diff --git a/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsViewOptions.cs b/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsViewOptions.cs index 6f2f8ac0dae9d..0cbbf48bb8d37 100644 --- a/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsViewOptions.cs +++ b/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsViewOptions.cs @@ -2,25 +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.Collections.Immutable; -using System.Composition; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Options.Providers; namespace Microsoft.CodeAnalysis.Editor.InlineHints { internal sealed class InlineHintsViewOptions { - private const string FeatureName = "InlineHintsOptions"; - public static readonly Option2 DisplayAllHintsWhilePressingAltF1 = new( - FeatureName, "DisplayAllHintsWhilePressingAltF1", defaultValue: true, - storageLocation: new RoamingProfileStorageLocation("TextEditor.Specific.DisplayAllHintsWhilePressingAltF1")); + "InlineHintsOptions_DisplayAllHintsWhilePressingAltF1", defaultValue: true); public static readonly PerLanguageOption2 ColorHints = new( - FeatureName, "ColorHints", defaultValue: true, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ColorHints")); + "InlineHintsOptions_ColorHints", defaultValue: true); } } diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyout.xaml.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyout.xaml.cs index d352c9095557f..751014f12b16f 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyout.xaml.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyout.xaml.cs @@ -8,6 +8,7 @@ using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.VisualStudio.Language.Intellisense; using Microsoft.VisualStudio.PlatformUI; @@ -43,16 +44,14 @@ public RenameFlyout( // On load focus the first tab target Loaded += (s, e) => { + // Wait until load to position adornment for space negotiation + PositionAdornment(); + IdentifierTextBox.Focus(); IdentifierTextBox.Select(_viewModel.StartingSelection.Start, _viewModel.StartingSelection.Length); - - // Don't hook up our close events until we're done loading and have focused within the textbox - _textView.LostAggregateFocus += TextView_LostFocus; - IsKeyboardFocusWithinChanged += RenameFlyout_IsKeyboardFocusWithinChanged; }; InitializeComponent(); - PositionAdornment(); if (themeService is not null) { @@ -89,39 +88,6 @@ private async Task DismissToolTipsAsync() public string SubmitText => EditorFeaturesWpfResources.Enter_to_rename_shift_enter_to_preview; #pragma warning restore CA1822 // Mark members as static - private void RenameFlyout_IsKeyboardFocusWithinChanged(object sender, DependencyPropertyChangedEventArgs e) - { - // When previewing changes, focus will be lost and put - // into a preview changes window. If we're returning back - // to this UI, reset the flag to false. Otherwise, just ignore - // this focus change. No need to cancel in that case - if (_viewModel.PreviewChangesFlag) - { - if (IsKeyboardFocused) - { - _viewModel.PreviewChangesFlag = false; - } - - return; - } - - if (!IsKeyboardFocused) - { - _viewModel.Cancel(); - } - } - - private void TextView_LostFocus(object sender, EventArgs e) - { - // Preview changes is happening, no need to act on focus changes. - if (_viewModel.PreviewChangesFlag) - { - return; - } - - _viewModel.Cancel(); - } - private void TextView_ViewPortChanged(object sender, EventArgs e) => PositionAdornment(); @@ -138,8 +104,23 @@ private void TextView_LayoutChanged(object sender, TextViewLayoutChangedEventArg private void PositionAdornment() { - var top = _textView.Caret.Bottom + 5; - var left = _textView.Caret.Left - 5; + var span = _viewModel.InitialTrackingSpan.GetSpan(_textView.TextSnapshot); + var line = _textView.GetTextViewLineContainingBufferPosition(span.Start); + var charBounds = line.GetCharacterBounds(span.Start); + + var height = DesiredSize.Height; + var width = DesiredSize.Width; + + var desiredTop = charBounds.TextBottom + 5; + var desiredLeft = charBounds.Left; + + var top = (desiredTop + height) > _textView.ViewportBottom + ? _textView.ViewportBottom - height + : desiredTop; + + var left = (desiredLeft + width) > _textView.ViewportRight + ? _textView.ViewportRight - width + : desiredLeft; Canvas.SetTop(this, top); Canvas.SetLeft(this, left); @@ -152,7 +133,6 @@ public override void Dispose() _textView.LayoutChanged -= TextView_LayoutChanged; _textView.ViewportHeightChanged -= TextView_ViewPortChanged; _textView.ViewportWidthChanged -= TextView_ViewPortChanged; - _textView.LostAggregateFocus -= TextView_LostFocus; // Restore focus back to the textview _textView.VisualElement.Focus(); diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs index fa7f66223e9a6..e0542a456a1d3 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs @@ -12,6 +12,7 @@ using System.Windows.Interop; using Microsoft.CodeAnalysis.Editor.Implementation.InlineRename; using Microsoft.CodeAnalysis.Editor.InlineRename; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.InlineRename; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Rename; @@ -19,6 +20,7 @@ using Microsoft.VisualStudio.Imaging; using Microsoft.VisualStudio.Imaging.Interop; using Microsoft.VisualStudio.PlatformUI.OleComponentSupport; +using Microsoft.VisualStudio.Text; namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename { @@ -41,6 +43,7 @@ public RenameFlyoutViewModel(InlineRenameSession session, TextSpan selectionSpan _session.ReplacementsComputed += OnReplacementsComputed; _session.ReferenceLocationsChanged += OnReferenceLocationsChanged; StartingSelection = selectionSpan; + InitialTrackingSpan = session.TriggerSpan.CreateTrackingSpan(VisualStudio.Text.SpanTrackingMode.EdgeInclusive); RegisterOleComponent(); } @@ -60,6 +63,8 @@ public string IdentifierText public InlineRenameSession Session => _session; + public ITrackingSpan InitialTrackingSpan { get; } + public bool AllowFileRename => _session.FileRenameInfo == InlineRenameFileRenameInfo.Allowed && _isReplacementTextValid; public bool ShowFileRename => _session.FileRenameInfo != InlineRenameFileRenameInfo.NotAllowed; @@ -113,7 +118,7 @@ public bool RenameInCommentsFlag get => _session.Options.RenameInComments; set { - _globalOptionService.SetGlobalOption(new OptionKey(InlineRenameSessionOptionsStorage.RenameInComments), value); + _globalOptionService.SetGlobalOption(InlineRenameSessionOptionsStorage.RenameInComments, value); _session.RefreshRenameSessionWithOptionsChanged(_session.Options with { RenameInComments = value }); } } @@ -123,7 +128,7 @@ public bool RenameInStringsFlag get => _session.Options.RenameInStrings; set { - _globalOptionService.SetGlobalOption(new OptionKey(InlineRenameSessionOptionsStorage.RenameInStrings), value); + _globalOptionService.SetGlobalOption(InlineRenameSessionOptionsStorage.RenameInStrings, value); _session.RefreshRenameSessionWithOptionsChanged(_session.Options with { RenameInStrings = value }); } } @@ -133,7 +138,7 @@ public bool RenameFileFlag get => _session.Options.RenameFile; set { - _globalOptionService.SetGlobalOption(new OptionKey(InlineRenameSessionOptionsStorage.RenameFile), value); + _globalOptionService.SetGlobalOption(InlineRenameSessionOptionsStorage.RenameFile, value); _session.RefreshRenameSessionWithOptionsChanged(_session.Options with { RenameFile = value }); } } @@ -143,7 +148,7 @@ public bool PreviewChangesFlag get => _session.PreviewChanges; set { - _globalOptionService.SetGlobalOption(new OptionKey(InlineRenameSessionOptionsStorage.PreviewChanges), value); + _globalOptionService.SetGlobalOption(InlineRenameSessionOptionsStorage.PreviewChanges, value); _session.SetPreviewChanges(value); } } @@ -153,7 +158,7 @@ public bool RenameOverloadsFlag get => _session.Options.RenameOverloads; set { - _globalOptionService.SetGlobalOption(new OptionKey(InlineRenameSessionOptionsStorage.RenameOverloads), value); + _globalOptionService.SetGlobalOption(InlineRenameSessionOptionsStorage.RenameOverloads, value); _session.RefreshRenameSessionWithOptionsChanged(_session.Options with { RenameOverloads = value }); } } @@ -165,7 +170,7 @@ public bool IsCollapsed { if (value != IsCollapsed) { - _globalOptionService.SetGlobalOption(new OptionKey(InlineRenameUIOptions.CollapseUI), value); + _globalOptionService.SetGlobalOption(InlineRenameUIOptions.CollapseUI, value); NotifyPropertyChanged(nameof(IsCollapsed)); NotifyPropertyChanged(nameof(IsExpanded)); } diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboardViewModel.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboardViewModel.cs index 67bbcc63386c9..68ff29813023a 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboardViewModel.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboardViewModel.cs @@ -241,7 +241,7 @@ public bool DefaultRenameOverloadFlag { if (IsRenameOverloadsEditable) { - _session.RenameService.GlobalOptions.SetGlobalOption(new OptionKey(InlineRenameSessionOptionsStorage.RenameOverloads), value); + _session.RenameService.GlobalOptions.SetGlobalOption(InlineRenameSessionOptionsStorage.RenameOverloads, value); _session.RefreshRenameSessionWithOptionsChanged(_session.Options with { RenameOverloads = value }); } } @@ -253,7 +253,7 @@ public bool DefaultRenameInStringsFlag set { - _session.RenameService.GlobalOptions.SetGlobalOption(new OptionKey(InlineRenameSessionOptionsStorage.RenameInStrings), value); + _session.RenameService.GlobalOptions.SetGlobalOption(InlineRenameSessionOptionsStorage.RenameInStrings, value); _session.RefreshRenameSessionWithOptionsChanged(_session.Options with { RenameInStrings = value }); } } @@ -264,7 +264,7 @@ public bool DefaultRenameInCommentsFlag set { - _session.RenameService.GlobalOptions.SetGlobalOption(new OptionKey(InlineRenameSessionOptionsStorage.RenameInComments), value); + _session.RenameService.GlobalOptions.SetGlobalOption(InlineRenameSessionOptionsStorage.RenameInComments, value); _session.RefreshRenameSessionWithOptionsChanged(_session.Options with { RenameInComments = value }); } } @@ -274,7 +274,7 @@ public bool DefaultRenameFileFlag get => _session.Options.RenameFile; set { - _session.RenameService.GlobalOptions.SetGlobalOption(new OptionKey(InlineRenameSessionOptionsStorage.RenameFile), value); + _session.RenameService.GlobalOptions.SetGlobalOption(InlineRenameSessionOptionsStorage.RenameFile, value); _session.RefreshRenameSessionWithOptionsChanged(_session.Options with { RenameFile = value }); } } @@ -285,7 +285,7 @@ public bool DefaultPreviewChangesFlag set { - _session.RenameService.GlobalOptions.SetGlobalOption(new OptionKey(InlineRenameSessionOptionsStorage.PreviewChanges), value); + _session.RenameService.GlobalOptions.SetGlobalOption(InlineRenameSessionOptionsStorage.PreviewChanges, value); _session.SetPreviewChanges(value); } } diff --git a/src/EditorFeatures/Core.Wpf/LineSeparators/LineSeparatorTaggerProvider.cs b/src/EditorFeatures/Core.Wpf/LineSeparators/LineSeparatorTaggerProvider.cs index 46aa0e57bd16b..760b0bb49ab22 100644 --- a/src/EditorFeatures/Core.Wpf/LineSeparators/LineSeparatorTaggerProvider.cs +++ b/src/EditorFeatures/Core.Wpf/LineSeparators/LineSeparatorTaggerProvider.cs @@ -44,7 +44,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; } = ImmutableArray.Empty; private readonly object _lineSeparatorTagGate = new(); private LineSeparatorTag _lineSeparatorTag; diff --git a/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemProvider.Callback.cs b/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemProvider.Callback.cs index 3f581f2513791..7c1ff6aa7b44d 100644 --- a/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemProvider.Callback.cs +++ b/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemProvider.Callback.cs @@ -2,8 +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. +using System; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.NavigateTo; using Microsoft.CodeAnalysis.Text.Shared.Extensions; using Microsoft.VisualStudio.Language.NavigateTo.Interfaces; @@ -70,7 +72,18 @@ private void ReportMatchResult(Project project, INavigateToSearchResult result) result, patternMatch, _displayFactory); - _callback.AddItem(navigateToItem); + + try + { + _callback.AddItem(navigateToItem); + } + catch (InvalidOperationException ex) when (FatalError.ReportAndCatch(ex, ErrorSeverity.Critical)) + { + // Mitigation for race condition in platform https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1534364 + // + // Catch this so that don't tear down OOP, but still report the exception so that we ensure this issue + // gets attention and is fixed. + } } private static PatternMatchKind GetPatternMatchKind(NavigateToMatchKind matchKind) diff --git a/src/EditorFeatures/Core.Wpf/StringIndentation/StringIndentationTaggerProvider.cs b/src/EditorFeatures/Core.Wpf/StringIndentation/StringIndentationTaggerProvider.cs index 93f01893ef8a3..452b8f0fa2ec1 100644 --- a/src/EditorFeatures/Core.Wpf/StringIndentation/StringIndentationTaggerProvider.cs +++ b/src/EditorFeatures/Core.Wpf/StringIndentation/StringIndentationTaggerProvider.cs @@ -40,7 +40,7 @@ internal sealed partial class StringIndentationTaggerProvider : AsynchronousTagg { private readonly IEditorFormatMap _editorFormatMap; - protected override ImmutableArray Options { get; } = ImmutableArray.Create(FeatureOnOffOptions.StringIdentation); + protected override ImmutableArray Options { get; } = ImmutableArray.Create(FeatureOnOffOptions.StringIdentation); [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] diff --git a/src/EditorFeatures/Core/AddImports/AbstractAddImportsPasteCommandHandler.cs b/src/EditorFeatures/Core/AddImports/AbstractAddImportsPasteCommandHandler.cs index 271cf6e61ab14..7212f9f4dc28d 100644 --- a/src/EditorFeatures/Core/AddImports/AbstractAddImportsPasteCommandHandler.cs +++ b/src/EditorFeatures/Core/AddImports/AbstractAddImportsPasteCommandHandler.cs @@ -56,8 +56,10 @@ public CommandState GetCommandState(PasteCommandArgs args, Func ne public void ExecuteCommand(PasteCommandArgs args, Action nextCommandHandler, CommandExecutionContext executionContext) { + var language = args.SubjectBuffer.GetLanguageName(); + // If the feature is not explicitly enabled we can exit early - if (!_globalOptions.GetOption(FeatureOnOffOptions.AddImportsOnPaste, args.SubjectBuffer.GetLanguageName())) + if (language is null || !_globalOptions.GetOption(FeatureOnOffOptions.AddImportsOnPaste, language)) { nextCommandHandler(); return; diff --git a/src/EditorFeatures/Core/BraceMatching/BraceHighlightingViewTaggerProvider.cs b/src/EditorFeatures/Core/BraceMatching/BraceHighlightingViewTaggerProvider.cs index df3083c999a85..4864cd0801760 100644 --- a/src/EditorFeatures/Core/BraceMatching/BraceHighlightingViewTaggerProvider.cs +++ b/src/EditorFeatures/Core/BraceMatching/BraceHighlightingViewTaggerProvider.cs @@ -35,7 +35,7 @@ internal sealed class BraceHighlightingViewTaggerProvider : AsynchronousViewTagg { private readonly IBraceMatchingService _braceMatcherService; - protected sealed override ImmutableArray Options { get; } = ImmutableArray.Create(InternalFeatureOnOffOptions.BraceMatching); + protected sealed override ImmutableArray Options { get; } = ImmutableArray.Create(InternalFeatureOnOffOptions.BraceMatching); [ImportingConstructor] [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] diff --git a/src/EditorFeatures/Core/Classification/Semantic/AbstractSemanticOrEmbeddedClassificationViewTaggerProvider.cs b/src/EditorFeatures/Core/Classification/Semantic/AbstractSemanticOrEmbeddedClassificationViewTaggerProvider.cs index fdafda0240f7d..1ec853cf07491 100644 --- a/src/EditorFeatures/Core/Classification/Semantic/AbstractSemanticOrEmbeddedClassificationViewTaggerProvider.cs +++ b/src/EditorFeatures/Core/Classification/Semantic/AbstractSemanticOrEmbeddedClassificationViewTaggerProvider.cs @@ -40,7 +40,7 @@ internal abstract class AbstractSemanticOrEmbeddedClassificationViewTaggerProvid // We want to track text changes so that we can try to only reclassify a method body if // all edits were contained within one. protected sealed override TaggerTextChangeBehavior TextChangeBehavior => TaggerTextChangeBehavior.TrackTextChanges; - protected sealed override ImmutableArray Options { get; } = ImmutableArray.Create(InternalFeatureOnOffOptions.SemanticColorizer); + protected sealed override ImmutableArray Options { get; } = ImmutableArray.Create(InternalFeatureOnOffOptions.SemanticColorizer); protected AbstractSemanticOrEmbeddedClassificationViewTaggerProvider( IThreadingContext threadingContext, diff --git a/src/EditorFeatures/Core/Diagnostics/AbstractPushOrPullDiagnosticsTaggerProvider.SingleDiagnosticKindPullTaggerProvider.cs b/src/EditorFeatures/Core/Diagnostics/AbstractPushOrPullDiagnosticsTaggerProvider.SingleDiagnosticKindPullTaggerProvider.cs index 2a36f5953f529..0e3ee857f11a8 100644 --- a/src/EditorFeatures/Core/Diagnostics/AbstractPushOrPullDiagnosticsTaggerProvider.SingleDiagnosticKindPullTaggerProvider.cs +++ b/src/EditorFeatures/Core/Diagnostics/AbstractPushOrPullDiagnosticsTaggerProvider.SingleDiagnosticKindPullTaggerProvider.cs @@ -15,6 +15,7 @@ using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Editor.Tagging; using Microsoft.CodeAnalysis.ErrorReporting; +using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -43,7 +44,7 @@ private sealed class SingleDiagnosticKindPullTaggerProvider : AsynchronousTagger private readonly AbstractPushOrPullDiagnosticsTaggerProvider _callback; - protected override ImmutableArray Options => _callback.Options; + protected override ImmutableArray Options => _callback.Options; public SingleDiagnosticKindPullTaggerProvider( AbstractPushOrPullDiagnosticsTaggerProvider callback, @@ -98,7 +99,8 @@ private async Task ProduceTagsAsync( var snapshot = documentSpanToTag.SnapshotSpan.Snapshot; - var workspace = document.Project.Solution.Workspace; + var project = document.Project; + var workspace = project.Solution.Workspace; // See if we've marked any spans as those we want to suppress diagnostics for. // This can happen for buffers used in the preview workspace where some feature @@ -117,9 +119,12 @@ private async Task ProduceTagsAsync( // correct project info to get reasonable results. if (_diagnosticKind != DiagnosticKind.CompilerSyntax) { + var service = project.Solution.Services.GetRequiredService(); + if (!await service.IsFullyLoadedAsync(cancellationToken).ConfigureAwait(false)) + return; + using var _ = PooledHashSet.GetInstance(out var seenProjects); - var hasSuccessfullyLoaded = HasSuccessfullyLoaded(document.Project, seenProjects); - if (!hasSuccessfullyLoaded) + if (!HasSuccessfullyLoaded(document.Project, seenProjects)) return; } diff --git a/src/EditorFeatures/Core/Diagnostics/AbstractPushOrPullDiagnosticsTaggerProvider.cs b/src/EditorFeatures/Core/Diagnostics/AbstractPushOrPullDiagnosticsTaggerProvider.cs index fcdeabba5442c..b0094aafd4920 100644 --- a/src/EditorFeatures/Core/Diagnostics/AbstractPushOrPullDiagnosticsTaggerProvider.cs +++ b/src/EditorFeatures/Core/Diagnostics/AbstractPushOrPullDiagnosticsTaggerProvider.cs @@ -19,8 +19,7 @@ namespace Microsoft.CodeAnalysis.Diagnostics; internal static class DiagnosticTaggingOptions { public static readonly Option2 PullDiagnosticTagging = new( - "DiagnosticTaggingOptions", "PullDiagnosticTagging", defaultValue: true, - new FeatureFlagStorageLocation("Roslyn.PullDiagnosticTagging")); + "DiagnosticTaggingOptions_PullDiagnosticTagging", defaultValue: true); } /// @@ -92,8 +91,8 @@ private static ITaggerEventSource CreateEventSourceWorker(ITextBuffer subjectBuf // SingleDiagnosticKindTaggerProvider will defer to these to do the work so that they otherwise operate // identically. - protected abstract ImmutableArray Options { get; } - protected virtual ImmutableArray FeatureOptions { get; } = ImmutableArray.Empty; + protected abstract ImmutableArray Options { get; } + protected virtual ImmutableArray FeatureOptions { get; } = ImmutableArray.Empty; protected abstract bool IsEnabled { get; } diff --git a/src/EditorFeatures/Core/Diagnostics/DiagnosticsClassificationTaggerProvider.cs b/src/EditorFeatures/Core/Diagnostics/DiagnosticsClassificationTaggerProvider.cs index 351fce76ce34e..4f456db4bd76b 100644 --- a/src/EditorFeatures/Core/Diagnostics/DiagnosticsClassificationTaggerProvider.cs +++ b/src/EditorFeatures/Core/Diagnostics/DiagnosticsClassificationTaggerProvider.cs @@ -37,7 +37,7 @@ internal sealed partial class DiagnosticsClassificationTaggerProvider : Abstract private readonly ClassificationTag _classificationTag; private readonly EditorOptionsService _editorOptionsService; - protected sealed override ImmutableArray Options { get; } = ImmutableArray.Create(InternalFeatureOnOffOptions.Classification); + protected sealed override ImmutableArray Options { get; } = ImmutableArray.Create(InternalFeatureOnOffOptions.Classification); [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] diff --git a/src/EditorFeatures/Core/Diagnostics/DiagnosticsSquiggleTaggerProvider.cs b/src/EditorFeatures/Core/Diagnostics/DiagnosticsSquiggleTaggerProvider.cs index ebcbdad495b40..2d7ef33678da2 100644 --- a/src/EditorFeatures/Core/Diagnostics/DiagnosticsSquiggleTaggerProvider.cs +++ b/src/EditorFeatures/Core/Diagnostics/DiagnosticsSquiggleTaggerProvider.cs @@ -28,7 +28,7 @@ namespace Microsoft.CodeAnalysis.Diagnostics [TagType(typeof(IErrorTag))] internal sealed partial class DiagnosticsSquiggleTaggerProvider : AbstractDiagnosticsAdornmentTaggerProvider { - protected override ImmutableArray Options { get; } = ImmutableArray.Create(InternalFeatureOnOffOptions.Squiggles); + protected override ImmutableArray Options { get; } = ImmutableArray.Create(InternalFeatureOnOffOptions.Squiggles); [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] diff --git a/src/EditorFeatures/Core/Diagnostics/DiagnosticsSuggestionTaggerProvider.cs b/src/EditorFeatures/Core/Diagnostics/DiagnosticsSuggestionTaggerProvider.cs index 5071134f8c211..bddf81034b661 100644 --- a/src/EditorFeatures/Core/Diagnostics/DiagnosticsSuggestionTaggerProvider.cs +++ b/src/EditorFeatures/Core/Diagnostics/DiagnosticsSuggestionTaggerProvider.cs @@ -28,7 +28,7 @@ namespace Microsoft.CodeAnalysis.Diagnostics internal sealed partial class DiagnosticsSuggestionTaggerProvider : AbstractDiagnosticsAdornmentTaggerProvider { - protected sealed override ImmutableArray Options { get; } = ImmutableArray.Create(InternalFeatureOnOffOptions.Squiggles); + protected sealed override ImmutableArray Options { get; } = ImmutableArray.Create(InternalFeatureOnOffOptions.Squiggles); [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyleSetting.cs b/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyleSetting.cs index 0451a0a6ce8bf..412ebe52f8025 100644 --- a/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyleSetting.cs +++ b/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyleSetting.cs @@ -14,8 +14,8 @@ internal abstract class CodeStyleSetting : Setting { private static readonly bool[] s_boolValues = new[] { true, false }; - public CodeStyleSetting(IOptionWithGroup option, OptionKey2 optionKey, string description, OptionUpdater updater, SettingLocation location) - : base(option, optionKey, description, updater, location) + public CodeStyleSetting(OptionKey2 optionKey, string description, OptionUpdater updater, SettingLocation location) + : base(optionKey, description, updater, location) { } @@ -68,7 +68,7 @@ internal static CodeStyleSetting Create( falseValueDescription ?? EditorFeaturesResources.No }; - return new CodeStyleSetting(option, optionKey, description, updater, initialLocation, initialValue, s_boolValues, valueDescriptions); + return new CodeStyleSetting(optionKey, description, updater, initialLocation, initialValue, s_boolValues, valueDescriptions); } internal static CodeStyleSetting Create( @@ -88,7 +88,7 @@ internal static CodeStyleSetting Create( falseValueDescription ?? EditorFeaturesResources.No }; - return new CodeStyleSetting(option, optionKey, description, updater, initialLocation, initialValue, s_boolValues, valueDescriptions); + return new CodeStyleSetting(optionKey, description, updater, initialLocation, initialValue, s_boolValues, valueDescriptions); } internal static CodeStyleSetting Create( @@ -102,7 +102,7 @@ internal static CodeStyleSetting Create( { var optionKey = new OptionKey2(option); options.GetInitialLocationAndValue>(option, out var initialLocation, out var initialValue); - return new CodeStyleSetting(option, optionKey, description, updater, initialLocation, initialValue, enumValues, valueDescriptions); + return new CodeStyleSetting(optionKey, description, updater, initialLocation, initialValue, enumValues, valueDescriptions); } internal static CodeStyleSetting Create( @@ -116,7 +116,7 @@ internal static CodeStyleSetting Create( { var optionKey = new OptionKey2(option, options.Language); options.GetInitialLocationAndValue>(option, out var initialLocation, out var initialValue); - return new CodeStyleSetting(option, optionKey, description, updater, initialLocation, initialValue, enumValues, valueDescriptions); + return new CodeStyleSetting(optionKey, description, updater, initialLocation, initialValue, enumValues, valueDescriptions); } } } diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyleSetting`1.cs b/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyleSetting`1.cs index 6562d26e12788..2128c7af02ebc 100644 --- a/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyleSetting`1.cs +++ b/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyleSetting`1.cs @@ -23,7 +23,6 @@ internal sealed class CodeStyleSetting : CodeStyleSetting private CodeStyleOption2 _value; public CodeStyleSetting( - IOptionWithGroup option, OptionKey2 optionKey, string description, OptionUpdater updater, @@ -31,7 +30,7 @@ public CodeStyleSetting( CodeStyleOption2 initialValue, T[] possibleValues, string[] valueDescriptions) - : base(option, optionKey, description, updater, location) + : base(optionKey, description, updater, location) { Contract.ThrowIfFalse(possibleValues.Length == valueDescriptions.Length); diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Data/EnumFlagsSetting.cs b/src/EditorFeatures/Core/EditorConfigSettings/Data/EnumFlagsSetting.cs index cb41ad1831c41..084229f53a81a 100644 --- a/src/EditorFeatures/Core/EditorConfigSettings/Data/EnumFlagsSetting.cs +++ b/src/EditorFeatures/Core/EditorConfigSettings/Data/EnumFlagsSetting.cs @@ -22,7 +22,6 @@ internal sealed class EnumFlagsSetting : Setting private readonly StrongBox _valueStorage; public EnumFlagsSetting( - IOptionWithGroup option, OptionKey2 optionKey, string description, OptionUpdater updater, @@ -30,7 +29,7 @@ public EnumFlagsSetting( int flag, StrongBox valueStorage, Conversions conversions) - : base(option, optionKey, description, updater, location) + : base(optionKey, description, updater, location) { _flag = flag; _conversions = conversions; diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Data/Setting.cs b/src/EditorFeatures/Core/EditorConfigSettings/Data/Setting.cs index 107e61579fca6..fe0dd62a71476 100644 --- a/src/EditorFeatures/Core/EditorConfigSettings/Data/Setting.cs +++ b/src/EditorFeatures/Core/EditorConfigSettings/Data/Setting.cs @@ -12,16 +12,14 @@ namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data { internal abstract class Setting { - public IOptionWithGroup Option { get; } public OptionKey2 Key { get; } public OptionUpdater Updater { get; } public string Description { get; } public SettingLocation Location { get; private set; } - protected Setting(IOptionWithGroup option, OptionKey2 optionKey, string description, OptionUpdater updater, SettingLocation location) + protected Setting(OptionKey2 optionKey, string description, OptionUpdater updater, SettingLocation location) { - Option = option; Key = optionKey; Description = description; Updater = updater; @@ -35,10 +33,10 @@ protected Setting(IOptionWithGroup option, OptionKey2 optionKey, string descript public void SetValue(object value) { Location = Location with { LocationKind = LocationKind.EditorConfig }; - Updater.QueueUpdate(Option, UpdateValue(value)); + Updater.QueueUpdate(Key.Option, UpdateValue(value)); } - public string Category => Option.Group.Description; + public string Category => Key.Option.Definition.Group.Description; public bool IsDefinedInEditorConfig => Location.LocationKind != LocationKind.VisualStudio; public static Setting Create( @@ -50,7 +48,7 @@ public static Setting Create( { var optionKey = new OptionKey2(option); options.GetInitialLocationAndValue(option, out var initialLocation, out var initialValue); - return new Setting(option, optionKey, description, updater, initialLocation, initialValue); + return new Setting(optionKey, description, updater, initialLocation, initialValue); } public static Setting Create( @@ -63,7 +61,7 @@ public static Setting Create( // TODO: Support for other languages https://github.com/dotnet/roslyn/issues/65859 var optionKey = new OptionKey2(option, LanguageNames.CSharp); options.GetInitialLocationAndValue(option, out var initialLocation, out var initialValue); - return new Setting(option, optionKey, description, updater, initialLocation, initialValue); + return new Setting(optionKey, description, updater, initialLocation, initialValue); } public static EnumFlagsSetting CreateEnumFlags( @@ -79,7 +77,7 @@ public static EnumFlagsSetting CreateEnumFlags( var optionKey = new OptionKey2(option); options.GetInitialLocationAndValue(option, out var initialLocation, out var initialValue); valueStorage.Value = initialValue; - return new EnumFlagsSetting(option, optionKey, description, updater, initialLocation, flag, valueStorage, conversions); + return new EnumFlagsSetting(optionKey, description, updater, initialLocation, flag, valueStorage, conversions); } } } diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Data/Setting`1.cs b/src/EditorFeatures/Core/EditorConfigSettings/Data/Setting`1.cs index bef52cbceb58d..ea73fe762e100 100644 --- a/src/EditorFeatures/Core/EditorConfigSettings/Data/Setting`1.cs +++ b/src/EditorFeatures/Core/EditorConfigSettings/Data/Setting`1.cs @@ -16,13 +16,12 @@ internal sealed class Setting : Setting private TOptionValue _value; public Setting( - IOptionWithGroup option, OptionKey2 optionKey, string description, OptionUpdater updater, SettingLocation location, TOptionValue initialValue) - : base(option, optionKey, description, updater, location) + : base(optionKey, description, updater, location) { _value = initialValue; } diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Data/TieredAnalyzerConfigOptions.cs b/src/EditorFeatures/Core/EditorConfigSettings/Data/TieredAnalyzerConfigOptions.cs index d3886b8e1afba..c039558ea51ff 100644 --- a/src/EditorFeatures/Core/EditorConfigSettings/Data/TieredAnalyzerConfigOptions.cs +++ b/src/EditorFeatures/Core/EditorConfigSettings/Data/TieredAnalyzerConfigOptions.cs @@ -2,23 +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. -using System; -using System.Collections.Generic; -using System.Text; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Options; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; internal sealed class TieredAnalyzerConfigOptions { public readonly AnalyzerConfigOptions EditorConfigOptions; - public readonly AnalyzerConfigOptions GlobalOptions; + public readonly IGlobalOptionService GlobalOptions; + public readonly string EditorConfigFileName; public readonly string Language; - public TieredAnalyzerConfigOptions(AnalyzerConfigOptions editorConfigOptions, AnalyzerConfigOptions globalOptions, string language, string editorConfigFileName) + public TieredAnalyzerConfigOptions(AnalyzerConfigOptions editorConfigOptions, IGlobalOptionService globalOptions, string language, string editorConfigFileName) { EditorConfigOptions = editorConfigOptions; GlobalOptions = globalOptions; @@ -27,7 +24,7 @@ public TieredAnalyzerConfigOptions(AnalyzerConfigOptions editorConfigOptions, An } public void GetInitialLocationAndValue( - IOption option, + IOption2 option, out SettingLocation location, out TValue initialValue) where TValue : notnull @@ -37,15 +34,10 @@ public void GetInitialLocationAndValue( location = new SettingLocation(LocationKind.EditorConfig, EditorConfigFileName); initialValue = editorConfigValue; } - else if (GlobalOptions.TryGetEditorConfigOption(option, out var globalValue)) - { - location = new SettingLocation(LocationKind.VisualStudio, EditorConfigFileName); - initialValue = globalValue; - } else { - // specified option is not an editorcondig option - throw ExceptionUtilities.Unreachable(); + location = new SettingLocation(LocationKind.VisualStudio, Path: null); + initialValue = GlobalOptions.GetOption(new OptionKey2(option, option.IsPerLanguage ? Language : null))!; } } } diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsProvider.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsProvider.cs index 4a103d11bf8c0..569a53340fca1 100644 --- a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsProvider.cs +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsProvider.cs @@ -6,23 +6,21 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using System.Threading.Tasks; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Extensions; using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; using Microsoft.CodeAnalysis.EditorConfig; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider.Analyzer { - internal class AnalyzerSettingsProvider : SettingsProviderBase + internal sealed class AnalyzerSettingsProvider : SettingsProviderBase { private readonly IDiagnosticAnalyzerService _analyzerService; public AnalyzerSettingsProvider(string fileName, AnalyzerSettingsUpdater settingsUpdater, Workspace workspace, IDiagnosticAnalyzerService analyzerService) - : base(fileName, settingsUpdater, workspace) + : base(fileName, settingsUpdater, workspace, analyzerService.GlobalOptions) { _analyzerService = analyzerService; Update(); diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/NamingStyles/NamingStyleSettingsProvider.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/NamingStyles/NamingStyleSettingsProvider.cs index 0d70619e1f916..d3e6b5140e9fa 100644 --- a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/NamingStyles/NamingStyleSettingsProvider.cs +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/NamingStyles/NamingStyleSettingsProvider.cs @@ -11,13 +11,14 @@ using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Extensions; using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider.NamingStyles { internal class NamingStyleSettingsProvider : SettingsProviderBase, NamingStyleSetting), object> { - public NamingStyleSettingsProvider(string fileName, NamingStyleSettingsUpdater settingsUpdater, Workspace workspace) - : base(fileName, settingsUpdater, workspace) + public NamingStyleSettingsProvider(string fileName, NamingStyleSettingsUpdater settingsUpdater, Workspace workspace, IGlobalOptionService globalOptions) + : base(fileName, settingsUpdater, workspace, globalOptions) { Update(); } diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/NamingStyles/NamingStyleSettingsProviderFactory.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/NamingStyles/NamingStyleSettingsProviderFactory.cs index 3dfe565a8fecc..9bb43e515d43d 100644 --- a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/NamingStyles/NamingStyleSettingsProviderFactory.cs +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/NamingStyles/NamingStyleSettingsProviderFactory.cs @@ -4,19 +4,25 @@ using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider.NamingStyles { - internal class NamingStyleSettingsProviderFactory : IWorkspaceSettingsProviderFactory + internal sealed class NamingStyleSettingsProviderFactory : IWorkspaceSettingsProviderFactory { private readonly Workspace _workspace; + private readonly IGlobalOptionService _globalOptions; - public NamingStyleSettingsProviderFactory(Workspace workspace) => _workspace = workspace; + public NamingStyleSettingsProviderFactory(Workspace workspace, IGlobalOptionService globalOptions) + { + _workspace = workspace; + _globalOptions = globalOptions; + } public ISettingsProvider GetForFile(string filePath) { - var updater = new NamingStyleSettingsUpdater(_workspace, filePath); - return new NamingStyleSettingsProvider(filePath, updater, _workspace); + var updater = new NamingStyleSettingsUpdater(_workspace, _globalOptions, filePath); + return new NamingStyleSettingsProvider(filePath, updater, _workspace, _globalOptions); } } } diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/NamingStyles/NamingStyleSettingsWorkspaceServiceFactory.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/NamingStyles/NamingStyleSettingsWorkspaceServiceFactory.cs index 3a9643447ab63..28b808e112bc9 100644 --- a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/NamingStyles/NamingStyleSettingsWorkspaceServiceFactory.cs +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/NamingStyles/NamingStyleSettingsWorkspaceServiceFactory.cs @@ -7,19 +7,23 @@ using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider.NamingStyles { [ExportWorkspaceServiceFactory(typeof(IWorkspaceSettingsProviderFactory)), Shared] - internal class NamingStyleSettingsWorkspaceServiceFactory : IWorkspaceServiceFactory + internal sealed class NamingStyleSettingsWorkspaceServiceFactory : IWorkspaceServiceFactory { + private readonly IGlobalOptionService _globalOptions; + [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public NamingStyleSettingsWorkspaceServiceFactory() + public NamingStyleSettingsWorkspaceServiceFactory(IGlobalOptionService globalOptions) { + _globalOptions = globalOptions; } public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) - => new NamingStyleSettingsProviderFactory(workspaceServices.Workspace); + => new NamingStyleSettingsProviderFactory(workspaceServices.Workspace, _globalOptions); } } diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/SettingsProviderBase.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/SettingsProviderBase.cs index 991d876d40356..7644c63e8ddf2 100644 --- a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/SettingsProviderBase.cs +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/SettingsProviderBase.cs @@ -31,14 +31,16 @@ internal abstract class SettingsProviderBase projectsInScope); - protected SettingsProviderBase(string fileName, TOptionsUpdater settingsUpdater, Workspace workspace) + protected SettingsProviderBase(string fileName, TOptionsUpdater settingsUpdater, Workspace workspace, IGlobalOptionService globalOptions) { FileName = fileName; SettingsUpdater = settingsUpdater; Workspace = workspace; + GlobalOptions = globalOptions; } protected void Update() @@ -53,15 +55,13 @@ protected void Update() return; } - var optionMappingService = solution.Services.GetRequiredService(); - var configFileDirectoryOptions = project.State.GetAnalyzerOptionsForPath(givenFolder.FullName, CancellationToken.None); var projectDirectoryOptions = project.GetAnalyzerConfigOptions(); // TODO: Support for multiple languages https://github.com/dotnet/roslyn/issues/65859 var options = new TieredAnalyzerConfigOptions( new CombinedAnalyzerConfigOptions(configFileDirectoryOptions, projectDirectoryOptions), - solution.Options.AsAnalyzerConfigOptions(optionMappingService, LanguageNames.CSharp), + GlobalOptions, language: LanguageNames.CSharp, editorConfigFileName: FileName); diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Updater/NamingStyles/NamingStyleSettingsUpdater.cs b/src/EditorFeatures/Core/EditorConfigSettings/Updater/NamingStyles/NamingStyleSettingsUpdater.cs index 57ad42ed21172..dfea933dbd0b8 100644 --- a/src/EditorFeatures/Core/EditorConfigSettings/Updater/NamingStyles/NamingStyleSettingsUpdater.cs +++ b/src/EditorFeatures/Core/EditorConfigSettings/Updater/NamingStyles/NamingStyleSettingsUpdater.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Extensions; using Microsoft.CodeAnalysis.EditorConfig.Parsing.NamingStyles; using Microsoft.CodeAnalysis.NamingStyles; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Text; using static Microsoft.CodeAnalysis.EditorConfig.Parsing.NamingStyles.EditorConfigNamingStylesParser; @@ -18,9 +19,12 @@ namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater { internal partial class NamingStyleSettingsUpdater : SettingsUpdaterBase<(Action<(object, object?)> onSettingChange, NamingStyleSetting option), object> { - public NamingStyleSettingsUpdater(Workspace workspace, string editorconfigPath) + public readonly IGlobalOptionService GlobalOptions; + + public NamingStyleSettingsUpdater(Workspace workspace, IGlobalOptionService globalOptions, string editorconfigPath) : base(workspace, editorconfigPath) { + GlobalOptions = globalOptions; } protected override SourceText? GetNewText( @@ -34,7 +38,7 @@ public NamingStyleSettingsUpdater(Workspace workspace, string editorconfigPath) // handle no naming style rules in the editorconfig file. // The implementation does not allow naming style rules to layer meaning all rules are either // defined in Visual Studios settings or in an editorconfig file. - analyzerConfigDocument = analyzerConfigDocument.WithNamingStyles(Workspace.Options); + analyzerConfigDocument = analyzerConfigDocument.WithNamingStyles(GlobalOptions); result = Parse(analyzerConfigDocument, EditorconfigPath); } diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Updater/NamingStyles/SourceTextExtensions.cs b/src/EditorFeatures/Core/EditorConfigSettings/Updater/NamingStyles/SourceTextExtensions.cs index f259cfd32e0b7..d5c546bcd20fc 100644 --- a/src/EditorFeatures/Core/EditorConfigSettings/Updater/NamingStyles/SourceTextExtensions.cs +++ b/src/EditorFeatures/Core/EditorConfigSettings/Updater/NamingStyles/SourceTextExtensions.cs @@ -12,7 +12,6 @@ using Microsoft.CodeAnalysis.EditorConfig.Parsing; using Microsoft.CodeAnalysis.NamingStyles; using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; using NamingStylesParser = Microsoft.CodeAnalysis.EditorConfig.Parsing.NamingStyles.EditorConfigNamingStylesParser; @@ -21,9 +20,9 @@ namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater { internal static class SourceTextExtensions { - public static SourceText WithNamingStyles(this SourceText sourceText, OptionSet options) + public static SourceText WithNamingStyles(this SourceText sourceText, IGlobalOptionService globalOptions) { - var (common, csharp, visualBasic) = GetPreferencesForAllLanguages(options); + var (common, csharp, visualBasic) = GetPreferencesForAllLanguages(globalOptions); sourceText = WithNamingStyles(sourceText, csharp, Language.CSharp); sourceText = WithNamingStyles(sourceText, visualBasic, Language.VisualBasic); @@ -79,10 +78,10 @@ static SourceText WithChanges(SourceText sourceText, TextSpan span, string newTe } } - private static (IEnumerable Common, IEnumerable CSharp, IEnumerable VisualBasic) GetPreferencesForAllLanguages(OptionSet options) + private static (IEnumerable Common, IEnumerable CSharp, IEnumerable VisualBasic) GetPreferencesForAllLanguages(IGlobalOptionService globalOptions) { - var csharpNamingStylePreferences = options.GetOption(NamingStyleOptions.NamingPreferences, LanguageNames.CSharp); - var vbNamingStylePreferences = options.GetOption(NamingStyleOptions.NamingPreferences, LanguageNames.VisualBasic); + var csharpNamingStylePreferences = globalOptions.GetOption(NamingStyleOptions.NamingPreferences, LanguageNames.CSharp); + var vbNamingStylePreferences = globalOptions.GetOption(NamingStyleOptions.NamingPreferences, LanguageNames.VisualBasic); var commonOptions = GetCommonOptions(csharpNamingStylePreferences, vbNamingStylePreferences); var csharpOnlyOptions = GetOptionsUniqueOptions(csharpNamingStylePreferences, commonOptions); diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Updater/SettingsUpdateHelper.cs b/src/EditorFeatures/Core/EditorConfigSettings/Updater/SettingsUpdateHelper.cs index 78c50270f204e..4e8d9d216f388 100644 --- a/src/EditorFeatures/Core/EditorConfigSettings/Updater/SettingsUpdateHelper.cs +++ b/src/EditorFeatures/Core/EditorConfigSettings/Updater/SettingsUpdateHelper.cs @@ -32,11 +32,9 @@ internal static partial class SettingsUpdateHelper if (filePath is null) return null; - var settings = settingsToUpdate.Select(x => TryGetOptionValueAndLanguage(x.option, x.value)).ToList(); + return TryUpdateAnalyzerConfigDocument(originalText, filePath, settingsToUpdate.Select(x => GetOptionValueAndLanguage(x.option, x.value))); - return TryUpdateAnalyzerConfigDocument(originalText, filePath, settings); - - static (string option, string value, Language language) TryGetOptionValueAndLanguage(AnalyzerSetting diagnostic, DiagnosticSeverity severity) + static (string option, string value, Language language) GetOptionValueAndLanguage(AnalyzerSetting diagnostic, DiagnosticSeverity severity) { var optionName = $"{DiagnosticOptionPrefix}{diagnostic.Id}{SeveritySuffix}"; var optionValue = severity.ToEditorConfigString(); @@ -57,23 +55,13 @@ internal static partial class SettingsUpdateHelper if (filePath is null) return null; - var updatedText = originalText; - var settings = settingsToUpdate.Select(x => TryGetOptionValueAndLanguage(x.option, x.value)) - .Where(x => x.success) - .Select(x => (x.option, x.value, x.language)) - .ToList(); - - return TryUpdateAnalyzerConfigDocument(originalText, filePath, settings); + return TryUpdateAnalyzerConfigDocument(originalText, filePath, settingsToUpdate.Select(x => GetOptionValueAndLanguage(x.option, x.value))); - static (bool success, string option, string value, Language language) TryGetOptionValueAndLanguage(IOption2 option, object value) + static (string option, string value, Language language) GetOptionValueAndLanguage(IOption2 option, object value) { - if (option.StorageLocations.FirstOrDefault(x => x is IEditorConfigStorageLocation2) is not IEditorConfigStorageLocation2 storageLocation) - { - return (false, null!, null!, default); - } + var optionName = option.Definition.ConfigName; + var optionValue = option.Definition.Serializer.Serialize(value); - var optionName = storageLocation.KeyName; - var optionValue = storageLocation.GetEditorConfigStringValue(value); if (value is ICodeStyleOption codeStyleOption && !optionValue.Contains(':')) { var severity = codeStyleOption.Notification.Severity switch @@ -98,7 +86,7 @@ internal static partial class SettingsUpdateHelper _ => throw ExceptionUtilities.UnexpectedValue(singleValuedOption.LanguageName), }; } - else if (option is IPerLanguageValuedOption perLanguageValuedOption) + else if (option.IsPerLanguage) { language = Language.CSharp | Language.VisualBasic; } @@ -107,21 +95,14 @@ internal static partial class SettingsUpdateHelper throw ExceptionUtilities.UnexpectedValue(option); } - return (true, optionName, optionValue, language); + return (optionName, optionValue, language); } } public static SourceText? TryUpdateAnalyzerConfigDocument(SourceText originalText, string filePath, - IReadOnlyList<(string option, string value, Language language)> settingsToUpdate) + IEnumerable<(string option, string value, Language language)> settingsToUpdate) { - if (originalText is null) - throw new ArgumentNullException(nameof(originalText)); - if (filePath is null) - throw new ArgumentNullException(nameof(filePath)); - if (settingsToUpdate is null) - throw new ArgumentNullException(nameof(settingsToUpdate)); - var updatedText = originalText; TextLine? lastValidHeaderSpanEnd; TextLine? lastValidSpecificHeaderSpanEnd; diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptGlobalOptions.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptGlobalOptions.cs index be1927b8062de..2e07016985570 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptGlobalOptions.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptGlobalOptions.cs @@ -26,17 +26,15 @@ public VSTypeScriptGlobalOptions(IGlobalOptionService globalOptions) public bool BlockForCompletionItems { get => _globalOptions.GetOption(CompletionViewOptions.BlockForCompletionItems, InternalLanguageNames.TypeScript); - set => _globalOptions.SetGlobalOption(new OptionKey(CompletionViewOptions.BlockForCompletionItems, InternalLanguageNames.TypeScript), value); + set => _globalOptions.SetGlobalOption(CompletionViewOptions.BlockForCompletionItems, InternalLanguageNames.TypeScript, value); } public void SetBackgroundAnalysisScope(bool openFilesOnly) { - _globalOptions.SetGlobalOption( - new OptionKey(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, InternalLanguageNames.TypeScript), + _globalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, InternalLanguageNames.TypeScript, openFilesOnly ? BackgroundAnalysisScope.OpenFiles : BackgroundAnalysisScope.FullSolution); - _globalOptions.SetGlobalOption( - new OptionKey(SolutionCrawlerOptionsStorage.RemoveDocumentDiagnosticsOnDocumentClose, InternalLanguageNames.TypeScript), + _globalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.RemoveDocumentDiagnosticsOnDocumentClose, InternalLanguageNames.TypeScript, openFilesOnly); } diff --git a/src/EditorFeatures/Core/ExtractMethod/ExtractMethodPresentationOptionsStorage.cs b/src/EditorFeatures/Core/ExtractMethod/ExtractMethodPresentationOptionsStorage.cs index 33dd95f566fd7..cfe5462982223 100644 --- a/src/EditorFeatures/Core/ExtractMethod/ExtractMethodPresentationOptionsStorage.cs +++ b/src/EditorFeatures/Core/ExtractMethod/ExtractMethodPresentationOptionsStorage.cs @@ -2,20 +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.Immutable; -using System.Composition; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Options.Providers; namespace Microsoft.CodeAnalysis.ExtractMethod { internal static class ExtractMethodPresentationOptionsStorage { - private const string FeatureName = "ExtractMethodOptions"; - - public static readonly PerLanguageOption2 AllowBestEffort = new(FeatureName, "AllowBestEffort", defaultValue: true, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.Allow Best Effort")); + public static readonly PerLanguageOption2 AllowBestEffort = new("ExtractMethodOptions_AllowBestEffort", defaultValue: true); } } diff --git a/src/EditorFeatures/Core/Formatting/FormattingOptionsMetadata.cs b/src/EditorFeatures/Core/Formatting/FormattingOptionsMetadata.cs index 71bafe47aa4ed..cc1c4dd0db645 100644 --- a/src/EditorFeatures/Core/Formatting/FormattingOptionsMetadata.cs +++ b/src/EditorFeatures/Core/Formatting/FormattingOptionsMetadata.cs @@ -8,10 +8,7 @@ namespace Microsoft.CodeAnalysis.Formatting { internal sealed class FormattingOptionsMetadata { - private const string FeatureName = "FormattingOptions"; - public static readonly PerLanguageOption2 FormatOnPaste = - new(FeatureName, OptionGroup.Default, "FormatOnPaste", defaultValue: true, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.FormatOnPaste")); + new("FormattingOptions_FormatOnPaste", defaultValue: true); } } diff --git a/src/EditorFeatures/Core/InlineDiagnostics/InlineDiagnosticsOptions.cs b/src/EditorFeatures/Core/InlineDiagnostics/InlineDiagnosticsOptions.cs index 6d490bb641834..0d60b5e672935 100644 --- a/src/EditorFeatures/Core/InlineDiagnostics/InlineDiagnosticsOptions.cs +++ b/src/EditorFeatures/Core/InlineDiagnostics/InlineDiagnosticsOptions.cs @@ -2,27 +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. -using System; -using System.Collections.Immutable; -using System.Composition; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Options.Providers; namespace Microsoft.CodeAnalysis.Editor.InlineDiagnostics { internal sealed class InlineDiagnosticsOptions { public static readonly PerLanguageOption2 EnableInlineDiagnostics = - new("InlineDiagnosticsOptions", - "EnableInlineDiagnostics", - defaultValue: false, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.InlineDiagnostics")); + new("InlineDiagnosticsOptions_EnableInlineDiagnostics", + defaultValue: false); public static readonly PerLanguageOption2 Location = - new("InlineDiagnosticsOptions", - "Location", - defaultValue: InlineDiagnosticsLocations.PlacedAtEndOfCode, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.InlineDiagnostics.LocationOption")); + new("InlineDiagnosticsOptions_Location", + defaultValue: InlineDiagnosticsLocations.PlacedAtEndOfCode); } } diff --git a/src/EditorFeatures/Core/InlineHints/InlineHintsGlobalStateOption.cs b/src/EditorFeatures/Core/InlineHints/InlineHintsGlobalStateOption.cs index 20f67b7fbf050..fc70d35430871 100644 --- a/src/EditorFeatures/Core/InlineHints/InlineHintsGlobalStateOption.cs +++ b/src/EditorFeatures/Core/InlineHints/InlineHintsGlobalStateOption.cs @@ -15,6 +15,6 @@ internal sealed class InlineHintsGlobalStateOption /// Non-persisted option used to switch to displaying everything while the user is holding ctrl-alt. /// public static readonly Option2 DisplayAllOverride = - new("InlineHintsOptions", "DisplayAllOverride", defaultValue: false); + new("InlineHintsOptions_DisplayAllOverride", defaultValue: false); } } diff --git a/src/EditorFeatures/Core/InlineHints/InlineHintsOptionsStorage.cs b/src/EditorFeatures/Core/InlineHints/InlineHintsOptionsStorage.cs index 476b8e307639d..e06881455d7b0 100644 --- a/src/EditorFeatures/Core/InlineHints/InlineHintsOptionsStorage.cs +++ b/src/EditorFeatures/Core/InlineHints/InlineHintsOptionsStorage.cs @@ -39,82 +39,56 @@ public static InlineTypeHintsOptions GetInlineTypeHintsOptions(this IGlobalOptio ForImplicitObjectCreation = globalOptions.GetOption(ForImplicitObjectCreation, language), }; - private const string FeatureName = "InlineHintsOptions"; - // Parameter hints public static readonly PerLanguageOption2 EnabledForParameters = - new(FeatureName, - nameof(EnabledForParameters), - InlineParameterHintsOptions.Default.EnabledForParameters, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.InlineParameterNameHints")); + new("InlineHintsOptions_EnabledForParameters", + InlineParameterHintsOptions.Default.EnabledForParameters); public static readonly PerLanguageOption2 ForLiteralParameters = - new(FeatureName, - nameof(ForLiteralParameters), - InlineParameterHintsOptions.Default.ForLiteralParameters, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.InlineParameterNameHints.ForLiteralParameters")); + new("InlineHintsOptions_ForLiteralParameters", + InlineParameterHintsOptions.Default.ForLiteralParameters); public static readonly PerLanguageOption2 ForIndexerParameters = - new(FeatureName, - nameof(ForIndexerParameters), - InlineParameterHintsOptions.Default.ForIndexerParameters, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.InlineParameterNameHints.ForArrayIndexers")); + new("InlineHintsOptions_ForIndexerParameters", + InlineParameterHintsOptions.Default.ForIndexerParameters); public static readonly PerLanguageOption2 ForObjectCreationParameters = - new(FeatureName, - nameof(ForObjectCreationParameters), - InlineParameterHintsOptions.Default.ForObjectCreationParameters, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.InlineParameterNameHints.ForObjectCreationParameters")); + new("InlineHintsOptions_ForObjectCreationParameters", + InlineParameterHintsOptions.Default.ForObjectCreationParameters); public static readonly PerLanguageOption2 ForOtherParameters = - new(FeatureName, - nameof(ForOtherParameters), - InlineParameterHintsOptions.Default.ForOtherParameters, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.InlineParameterNameHints.ForOtherParameters")); + new("InlineHintsOptions_ForOtherParameters", + InlineParameterHintsOptions.Default.ForOtherParameters); public static readonly PerLanguageOption2 SuppressForParametersThatDifferOnlyBySuffix = - new(FeatureName, - nameof(SuppressForParametersThatDifferOnlyBySuffix), - InlineParameterHintsOptions.Default.SuppressForParametersThatDifferOnlyBySuffix, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.InlineParameterNameHints.SuppressForParametersThatDifferOnlyBySuffix")); + new("InlineHintsOptions_SuppressForParametersThatDifferOnlyBySuffix", + InlineParameterHintsOptions.Default.SuppressForParametersThatDifferOnlyBySuffix); public static readonly PerLanguageOption2 SuppressForParametersThatMatchMethodIntent = - new(FeatureName, - nameof(SuppressForParametersThatMatchMethodIntent), - InlineParameterHintsOptions.Default.SuppressForParametersThatMatchMethodIntent, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.InlineParameterNameHints.SuppressForParametersThatMatchMethodIntent")); + new("InlineHintsOptions_SuppressForParametersThatMatchMethodIntent", + InlineParameterHintsOptions.Default.SuppressForParametersThatMatchMethodIntent); public static readonly PerLanguageOption2 SuppressForParametersThatMatchArgumentName = - new(FeatureName, - nameof(SuppressForParametersThatMatchArgumentName), - InlineParameterHintsOptions.Default.SuppressForParametersThatMatchArgumentName, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.InlineParameterNameHints.SuppressForParametersThatMatchArgumentName")); + new("InlineHintsOptions_SuppressForParametersThatMatchArgumentName", + InlineParameterHintsOptions.Default.SuppressForParametersThatMatchArgumentName); // Type Hints public static readonly PerLanguageOption2 EnabledForTypes = - new(FeatureName, - nameof(EnabledForTypes), - defaultValue: InlineTypeHintsOptions.Default.EnabledForTypes, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.InlineTypeHints")); + new("InlineHintsOptions_EnabledForTypes", + defaultValue: InlineTypeHintsOptions.Default.EnabledForTypes); public static readonly PerLanguageOption2 ForImplicitVariableTypes = - new(FeatureName, - nameof(ForImplicitVariableTypes), - defaultValue: InlineTypeHintsOptions.Default.ForImplicitVariableTypes, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.InlineTypeHints.ForImplicitVariableTypes")); + new("InlineHintsOptions_ForImplicitVariableTypes", + defaultValue: InlineTypeHintsOptions.Default.ForImplicitVariableTypes); public static readonly PerLanguageOption2 ForLambdaParameterTypes = - new(FeatureName, - nameof(ForLambdaParameterTypes), - defaultValue: InlineTypeHintsOptions.Default.ForLambdaParameterTypes, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.InlineTypeHints.ForLambdaParameterTypes")); + new("InlineHintsOptions_ForLambdaParameterTypes", + defaultValue: InlineTypeHintsOptions.Default.ForLambdaParameterTypes); public static readonly PerLanguageOption2 ForImplicitObjectCreation = - new(FeatureName, - nameof(ForImplicitObjectCreation), - defaultValue: InlineTypeHintsOptions.Default.ForImplicitObjectCreation, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.InlineTypeHints.ForImplicitObjectCreation")); + new("InlineHintsOptions_ForImplicitObjectCreation", + defaultValue: InlineTypeHintsOptions.Default.ForImplicitObjectCreation); } } diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSessionOptionsStorage.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSessionOptionsStorage.cs index 470904fcaf7a9..7f5d12a23681b 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSessionOptionsStorage.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSessionOptionsStorage.cs @@ -8,13 +8,11 @@ namespace Microsoft.CodeAnalysis.InlineRename { internal static class InlineRenameSessionOptionsStorage { - private const string FeatureName = "InlineRenameSessionOptions"; - - public static readonly Option2 RenameOverloads = new(FeatureName, "RenameOverloads", defaultValue: false, storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.RenameOverloads")); - public static readonly Option2 RenameInStrings = new(FeatureName, "RenameInStrings", defaultValue: false, storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.RenameInStrings")); - public static readonly Option2 RenameInComments = new(FeatureName, "RenameInComments", defaultValue: false, storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.RenameInComments")); - public static readonly Option2 RenameFile = new(FeatureName, "RenameFile", defaultValue: true, storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.RenameFile")); - public static readonly Option2 PreviewChanges = new(FeatureName, "PreviewChanges", defaultValue: false, storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.PreviewRename")); - public static readonly Option2 RenameAsynchronously = new(FeatureName, "RenameAsynchronously", defaultValue: true, storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.RenameAsynchronously")); + public static readonly Option2 RenameOverloads = new("InlineRenameSessionOptions_RenameOverloads", defaultValue: false); + public static readonly Option2 RenameInStrings = new("InlineRenameSessionOptions_RenameInStrings", defaultValue: false); + public static readonly Option2 RenameInComments = new("InlineRenameSessionOptions_RenameInComments", defaultValue: false); + public static readonly Option2 RenameFile = new("InlineRenameSessionOptions_RenameFile", defaultValue: true); + public static readonly Option2 PreviewChanges = new("InlineRenameSessionOptions_PreviewChanges", defaultValue: false); + public static readonly Option2 RenameAsynchronously = new("InlineRenameSessionOptions_RenameAsynchronously", defaultValue: true); } } diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameUIOptions.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameUIOptions.cs index b9e15dae3acf6..5380799b60ba4 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameUIOptions.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameUIOptions.cs @@ -2,26 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.Editor.InlineRename { internal sealed class InlineRenameUIOptions { - private const string FeatureName = "InlineRename"; - - public static readonly Option2 UseInlineAdornment = new( - FeatureName, - name: "UseInlineAdornment", - defaultValue: true, - storageLocation: new RoamingProfileStorageLocation("TextEditor.RenameUseInlineAdornment")); - - public static readonly Option2 CollapseUI = new( - FeatureName, - name: "CollapseRenameUI", - defaultValue: false, - storageLocation: new RoamingProfileStorageLocation("TextEditor.CollapseRenameUI")); + public static readonly Option2 UseInlineAdornment = new("InlineRename_UseInlineAdornment", defaultValue: true); + public static readonly Option2 CollapseUI = new("InlineRename_CollapseRenameUI", defaultValue: false); } } diff --git a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/ItemManager.CompletionListUpdater.cs b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/ItemManager.CompletionListUpdater.cs index 862776fced7dc..fd5b32f6aab95 100644 --- a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/ItemManager.CompletionListUpdater.cs +++ b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/ItemManager.CompletionListUpdater.cs @@ -81,8 +81,8 @@ public CompletionListUpdater( // We prefer using the original snapshot, which should always be available from items provided by Roslyn's CompletionSource. // Only use data.Snapshot in the theoretically possible but rare case when all items we are handling are from some non-Roslyn CompletionSource. - var snapshotForDocument = TryGetInitialTriggerLocation(_snapshotData, out var intialTriggerLocation) - ? intialTriggerLocation.Snapshot + var snapshotForDocument = TryGetInitialTriggerLocation(_snapshotData, out var initialTriggerLocation) + ? initialTriggerLocation.Snapshot : _snapshotData.Snapshot; _document = snapshotForDocument?.TextBuffer.AsTextContainer().GetOpenDocumentInCurrentContext(); @@ -95,8 +95,8 @@ public CompletionListUpdater( // We can change this if get requests from partner teams. _completionHelper = CompletionHelper.GetHelper(_document); _filterMethod = _completionService == null - ? ((matchResults, text, filtereditemsBuilder) => CompletionService.FilterItems(_completionHelper, matchResults, text, filtereditemsBuilder)) - : ((matchResults, text, filtereditemsBuilder) => _completionService.FilterItems(_document, matchResults, text, filtereditemsBuilder)); + ? ((matchResults, text, filteredItemsBuilder) => CompletionService.FilterItems(_completionHelper, matchResults, text, filteredItemsBuilder)) + : ((matchResults, text, filteredItemsBuilder) => _completionService.FilterItems(_document, matchResults, text, filteredItemsBuilder)); // Nothing to highlight if user hasn't typed anything yet. _highlightMatchingPortions = _filterText.Length > 0 @@ -250,7 +250,7 @@ private void AddCompletionItems(List list, CancellationToken cancel if (CompletionItemData.TryGetData(item, out var itemData)) { - // currentIndex is used to track the index of the VS CompletionItem in the intial sorted list to maintain a map from Roslyn itemt o VS item. + // currentIndex is used to track the index of the VS CompletionItem in the initial sorted list to maintain a map from Roslyn item to VS item. // It's also used to sort the items by pattern matching results while preserving the original alphabetical order for items with // same pattern match score since `List.Sort` isn't stable. if (CompletionHelper.TryCreateMatchResult(_completionHelper, itemData.RoslynItem, _filterText, @@ -577,7 +577,7 @@ private ImmutableArray GetUpdatedFilters(IReadOnlyLis } /// - /// Given multiple possible chosen completion items, pick the one using the following perferences (in order): + /// Given multiple possible chosen completion items, pick the one using the following preferences (in order): /// 1. Most recently used item is our top preference /// 2. IntelliCode item over non-IntelliCode item /// 3. Higher MatchPriority @@ -645,18 +645,18 @@ private static MatchResult GetBestCompletionItemSelectionFromFilteredResults(IRe return bestResult; } - private static bool TryGetInitialTriggerLocation(AsyncCompletionSessionDataSnapshot data, out SnapshotPoint intialTriggerLocation) + private static bool TryGetInitialTriggerLocation(AsyncCompletionSessionDataSnapshot data, out SnapshotPoint initialTriggerLocation) { foreach (var item in data.InitialSortedItemList) { if (CompletionItemData.TryGetData(item, out var itemData) && itemData.TriggerLocation.HasValue) { - intialTriggerLocation = itemData.TriggerLocation.Value; + initialTriggerLocation = itemData.TriggerLocation.Value; return true; } } - intialTriggerLocation = default; + initialTriggerLocation = default; return false; } @@ -756,9 +756,10 @@ private ItemSelection UpdateSelectionBasedOnSuggestedDefaults(IReadOnlyList= MatchPriority.Preselect) + if (selectedItem.Rules.MatchPriority >= MatchPriority.Preselect && !selectedItem.IsPreferredItem()) return itemSelection; var tick = Environment.TickCount; @@ -774,7 +775,7 @@ private ItemSelection UpdateSelectionBasedOnSuggestedDefaults(IReadOnlyList - private ItemSelection GetDefaultsMatch(IReadOnlyList items, ItemSelection intialSelection, CancellationToken cancellationToken) + private ItemSelection GetDefaultsMatch(IReadOnlyList items, ItemSelection initialSelection, CancellationToken cancellationToken) { // Because the items are already sorted based on pattern-matching score, try to limit the range for the items we compare default with // by searching for the first "inferior" item, so we can avoid always going through the entire list. @@ -786,18 +787,18 @@ private ItemSelection GetDefaultsMatch(IReadOnlyList items, ItemSel } else { - var selectedItemMatch = items[intialSelection.SelectedItemIndex].PatternMatch; + var selectedItemMatch = items[initialSelection.SelectedItemIndex].PatternMatch; // It's possible that an item doesn't match filter text but still ended up being selected, this is because we just always keep all the // items in the list in some cases. For example, user brought up completion with ctrl-j or through deletion. // Don't bother changing the selection in such cases (since there's no match to the filter text in the list) if (!selectedItemMatch.HasValue) - return intialSelection; + return initialSelection; // Because the items are sorted based on pattern-matching score, the selectedIndex is in the middle of a range of // -- as far as the pattern matcher is concerned -- equivalent items (items with identical PatternMatch.Kind and IsCaseSensitive). // Find the last items in the range and use that to limit the items searched for from the defaults list. - inferiorItemIndex = intialSelection.SelectedItemIndex; + inferiorItemIndex = initialSelection.SelectedItemIndex; while (++inferiorItemIndex < items.Count) { var itemMatch = items[inferiorItemIndex].PatternMatch; @@ -818,18 +819,18 @@ private ItemSelection GetDefaultsMatch(IReadOnlyList items, ItemSel // so we just need to search for the first item that matches the suggested default. for (var i = 0; i < inferiorItemIndex; ++i) { - if (items[i].CompletionItem.DisplayText == defaultText) + if (items[i].CompletionItem.FilterText == defaultText) { // If user hasn't typed anything, we'd like to hard select the default item. // This way, they can easily commit the default item which matches what WLC shows. - var selectionHint = _filterText.Length == 0 ? UpdateSelectionHint.Selected : intialSelection.SelectionHint; - return intialSelection with { SelectedItemIndex = i, SelectionHint = selectionHint }; + var selectionHint = _filterText.Length == 0 ? UpdateSelectionHint.Selected : initialSelection.SelectionHint; + return initialSelection with { SelectedItemIndex = i, SelectionHint = selectionHint }; } } } // Don't change the original selection since there's no match to the defaults provided. - return intialSelection; + return initialSelection; } private sealed class FilterStateHelper diff --git a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/ItemManager.cs b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/ItemManager.cs index 841e5eb777e60..0ad035dac1bef 100644 --- a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/ItemManager.cs +++ b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/ItemManager.cs @@ -20,8 +20,6 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.AsyncComplet { internal sealed partial class ItemManager : IAsyncCompletionItemManager2 { - public const string AggressiveDefaultsMatchingOptionName = "AggressiveDefaultsMatchingOption"; - private readonly RecentItemsManager _recentItemsManager; private readonly IGlobalOptionService _globalOptions; @@ -37,7 +35,7 @@ public Task> SortCompletionListAsync( CancellationToken cancellationToken) { var stopwatch = SharedStopwatch.StartNew(); - var items = SortCompletionitems(data, cancellationToken).ToImmutableArray(); + var items = SortCompletionItems(data, cancellationToken).ToImmutableArray(); AsyncCompletionLogger.LogItemManagerSortTicksDataPoint(stopwatch.Elapsed); return Task.FromResult(items); @@ -49,13 +47,13 @@ public Task> SortCompletionItemListAsync( CancellationToken cancellationToken) { var stopwatch = SharedStopwatch.StartNew(); - var itemList = session.CreateCompletionList(SortCompletionitems(data, cancellationToken)); + var itemList = session.CreateCompletionList(SortCompletionItems(data, cancellationToken)); AsyncCompletionLogger.LogItemManagerSortTicksDataPoint(stopwatch.Elapsed); return Task.FromResult(itemList); } - private static SegmentedList SortCompletionitems(AsyncCompletionSessionInitialDataSnapshot data, CancellationToken cancellationToken) + private static SegmentedList SortCompletionItems(AsyncCompletionSessionInitialDataSnapshot data, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var items = new SegmentedList(data.InitialItemList.Count); diff --git a/src/EditorFeatures/Core/KeywordHighlighting/HighlighterViewTaggerProvider.cs b/src/EditorFeatures/Core/KeywordHighlighting/HighlighterViewTaggerProvider.cs index 1d921f266d1aa..276260c59e533 100644 --- a/src/EditorFeatures/Core/KeywordHighlighting/HighlighterViewTaggerProvider.cs +++ b/src/EditorFeatures/Core/KeywordHighlighting/HighlighterViewTaggerProvider.cs @@ -45,7 +45,7 @@ internal sealed class HighlighterViewTaggerProvider : AsynchronousViewTaggerProv protected override TaggerCaretChangeBehavior CaretChangeBehavior => TaggerCaretChangeBehavior.RemoveAllTagsOnCaretMoveOutsideOfTag; protected override TaggerTextChangeBehavior TextChangeBehavior => TaggerTextChangeBehavior.RemoveAllTags; - protected override ImmutableArray Options { get; } = ImmutableArray.Create(FeatureOnOffOptions.KeywordHighlighting); + protected override ImmutableArray Options { get; } = ImmutableArray.Create(FeatureOnOffOptions.KeywordHighlighting); [ImportingConstructor] [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] diff --git a/src/EditorFeatures/Core/Logging/FunctionIdOptions.cs b/src/EditorFeatures/Core/Logging/FunctionIdOptions.cs index 1e7b202684a96..efcd6744cab56 100644 --- a/src/EditorFeatures/Core/Logging/FunctionIdOptions.cs +++ b/src/EditorFeatures/Core/Logging/FunctionIdOptions.cs @@ -33,14 +33,13 @@ private static Option2 CreateOption(FunctionId id) // vsregedit delete local [hive name] HKCU Roslyn\Internal\Performance\FunctionId [function name] // // If you want to set it for the default hive, use "" as the hive name (i.e. an empty argument) - return new(nameof(FunctionIdOptions), name, defaultValue: false, - storageLocation: new LocalUserProfileStorageLocation(@"Roslyn\Internal\Performance\FunctionId\" + name)); + return new("FunctionIdOptions_" + name, defaultValue: false); } private static IEnumerable GetFunctionIds() => Enum.GetValues(typeof(FunctionId)).Cast(); - public static IEnumerable GetOptions() + public static IEnumerable GetOptions() => GetFunctionIds().Select(GetOption); public static Option2 GetOption(FunctionId id) diff --git a/src/EditorFeatures/Core/Options/CompletionViewOptions.cs b/src/EditorFeatures/Core/Options/CompletionViewOptions.cs index 0666f6428af73..b31f548f788aa 100644 --- a/src/EditorFeatures/Core/Options/CompletionViewOptions.cs +++ b/src/EditorFeatures/Core/Options/CompletionViewOptions.cs @@ -2,34 +2,23 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Collections.Immutable; -using System.Composition; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Options.Providers; namespace Microsoft.CodeAnalysis.Completion { internal sealed class CompletionViewOptions { - private const string FeatureName = "CompletionOptions"; - public static readonly PerLanguageOption2 HighlightMatchingPortionsOfCompletionListItems = - new(FeatureName, nameof(HighlightMatchingPortionsOfCompletionListItems), defaultValue: true, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.HighlightMatchingPortionsOfCompletionListItems")); + new("CompletionOptions_HighlightMatchingPortionsOfCompletionListItems", defaultValue: true); public static readonly PerLanguageOption2 ShowCompletionItemFilters = - new(FeatureName, nameof(ShowCompletionItemFilters), defaultValue: true, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ShowCompletionItemFilters")); + new("CompletionOptions_ShowCompletionItemFilters", defaultValue: true); // Use tri-value so the default state can be used to turn on the feature with experimentation service. public static readonly PerLanguageOption2 EnableArgumentCompletionSnippets = - new(FeatureName, nameof(EnableArgumentCompletionSnippets), defaultValue: null, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.EnableArgumentCompletionSnippets")); + new("CompletionOptions_EnableArgumentCompletionSnippets", defaultValue: null); public static readonly PerLanguageOption2 BlockForCompletionItems = - new(FeatureName, nameof(BlockForCompletionItems), defaultValue: true, - storageLocation: new RoamingProfileStorageLocation($"TextEditor.%LANGUAGE%.Specific.BlockForCompletionItems")); + new("CompletionOptions_BlockForCompletionItems", defaultValue: true); } } diff --git a/src/EditorFeatures/Core/Options/EditorAnalyzerConfigOptions.cs b/src/EditorFeatures/Core/Options/EditorAnalyzerConfigOptions.cs index 1952af29dc142..ed915e40fac02 100644 --- a/src/EditorFeatures/Core/Options/EditorAnalyzerConfigOptions.cs +++ b/src/EditorFeatures/Core/Options/EditorAnalyzerConfigOptions.cs @@ -7,6 +7,7 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; +using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Roslyn.Utilities; @@ -17,7 +18,7 @@ internal sealed class EditorAnalyzerConfigOptions : AnalyzerConfigOptions { private readonly IDictionary _configOptions; - public EditorAnalyzerConfigOptions(IEditorOptions editorOptions) + internal EditorAnalyzerConfigOptions(IEditorOptions editorOptions) { _configOptions = (editorOptions.GetOptionValue(DefaultOptions.RawCodingConventionsSnapshotOptionName) as IDictionary) ?? SpecializedCollections.EmptyDictionary(); @@ -61,4 +62,10 @@ private static bool IsLowercase(string str) return true; } } + + internal static partial class EditorOptionsExtensions + { + public static StructuredAnalyzerConfigOptions ToAnalyzerConfigOptions(this IEditorOptions editorOptions) + => StructuredAnalyzerConfigOptions.Create(new EditorAnalyzerConfigOptions(editorOptions)); + } } diff --git a/src/EditorFeatures/Core/Options/ExtensionManagerOptions.cs b/src/EditorFeatures/Core/Options/ExtensionManagerOptions.cs index 8e2fb3f1ae0dd..fc6af7860fc52 100644 --- a/src/EditorFeatures/Core/Options/ExtensionManagerOptions.cs +++ b/src/EditorFeatures/Core/Options/ExtensionManagerOptions.cs @@ -2,18 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Collections.Immutable; -using System.Composition; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Options.Providers; namespace Microsoft.CodeAnalysis.Editor.Options { internal sealed class ExtensionManagerOptions { - public static readonly Option2 DisableCrashingExtensions = new( - nameof(ExtensionManagerOptions), nameof(DisableCrashingExtensions), defaultValue: true); + // TODO: Will always have default value https://github.com/dotnet/roslyn/issues/66063 + public static readonly Option2 DisableCrashingExtensions = new("ExtensionManagerOptions_DisableCrashingExtensions", defaultValue: true); } } diff --git a/src/EditorFeatures/Core/Options/LegacyGlobalOptionsWorkspaceService.cs b/src/EditorFeatures/Core/Options/LegacyGlobalOptionsWorkspaceService.cs index ebd98a223530e..1ab4da03b1516 100644 --- a/src/EditorFeatures/Core/Options/LegacyGlobalOptionsWorkspaceService.cs +++ b/src/EditorFeatures/Core/Options/LegacyGlobalOptionsWorkspaceService.cs @@ -23,31 +23,23 @@ internal sealed class LegacyGlobalOptionsWorkspaceService : ILegacyGlobalOptions private readonly CodeActionOptionsStorage.Provider _provider; private static readonly Option2 s_generateOverridesOption = new( - "GenerateOverridesOptions", "SelectAll", defaultValue: true, - storageLocation: new RoamingProfileStorageLocation($"TextEditor.Specific.GenerateOverridesOptions.SelectAll")); + "GenerateOverridesOptions_SelectAll", defaultValue: true); private static readonly PerLanguageOption2 s_generateOperators = new( - "GenerateEqualsAndGetHashCodeFromMembersOptions", - "GenerateOperators", defaultValue: false, - storageLocation: new RoamingProfileStorageLocation( - "TextEditor.%LANGUAGE%.Specific.GenerateEqualsAndGetHashCodeFromMembersOptions.GenerateOperators")); + "GenerateEqualsAndGetHashCodeFromMembersOptions_GenerateOperators", + defaultValue: false); private static readonly PerLanguageOption2 s_implementIEquatable = new( - "GenerateEqualsAndGetHashCodeFromMembersOptions", - "ImplementIEquatable", defaultValue: false, - storageLocation: new RoamingProfileStorageLocation( - "TextEditor.%LANGUAGE%.Specific.GenerateEqualsAndGetHashCodeFromMembersOptions.ImplementIEquatable")); + "GenerateEqualsAndGetHashCodeFromMembersOptions_ImplementIEquatable", + defaultValue: false); private static readonly PerLanguageOption2 s_addNullChecks = new( - "GenerateConstructorFromMembersOptions", - "AddNullChecks", defaultValue: false, - storageLocation: new RoamingProfileStorageLocation( - $"TextEditor.%LANGUAGE%.Specific.GenerateConstructorFromMembersOptions.AddNullChecks")); + "GenerateConstructorFromMembersOptions_AddNullChecks", + defaultValue: false); internal static readonly PerLanguageOption2 AddNullChecksToConstructorsGeneratedFromMembers = new( - "GenerateConstructorFromMembersOptions", - "AddNullChecks", defaultValue: false, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.GenerateConstructorFromMembersOptions.AddNullChecks")); + "GenerateConstructorFromMembersOptions_AddNullChecks", + defaultValue: false); [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] @@ -60,7 +52,7 @@ public LegacyGlobalOptionsWorkspaceService(IGlobalOptionService globalOptions) public bool GenerateOverrides { get => _globalOptions.GetOption(s_generateOverridesOption); - set => _globalOptions.SetGlobalOption(new OptionKey(s_generateOverridesOption), value); + set => _globalOptions.SetGlobalOption(s_generateOverridesOption, value); } public bool RazorUseTabs @@ -73,7 +65,7 @@ public int RazorTabSize public bool InlineHintsOptionsDisplayAllOverride { get => _globalOptions.GetOption(InlineHintsGlobalStateOption.DisplayAllOverride); - set => _globalOptions.SetGlobalOption(new OptionKey(InlineHintsGlobalStateOption.DisplayAllOverride), value); + set => _globalOptions.SetGlobalOption(InlineHintsGlobalStateOption.DisplayAllOverride, value); } public CleanCodeGenerationOptionsProvider CleanCodeGenerationOptionsProvider @@ -83,18 +75,18 @@ public bool GetGenerateEqualsAndGetHashCodeFromMembersGenerateOperators(string l => _globalOptions.GetOption(s_implementIEquatable, language); public void SetGenerateEqualsAndGetHashCodeFromMembersGenerateOperators(string language, bool value) - => _globalOptions.SetGlobalOption(new OptionKey(s_generateOperators, language), value); + => _globalOptions.SetGlobalOption(s_generateOperators, language, value); public bool GetGenerateEqualsAndGetHashCodeFromMembersImplementIEquatable(string language) => _globalOptions.GetOption(s_implementIEquatable, language); public void SetGenerateEqualsAndGetHashCodeFromMembersImplementIEquatable(string language, bool value) - => _globalOptions.SetGlobalOption(new OptionKey(s_implementIEquatable, language), value); + => _globalOptions.SetGlobalOption(s_implementIEquatable, language, value); public bool GetGenerateConstructorFromMembersOptionsAddNullChecks(string language) => _globalOptions.GetOption(s_addNullChecks, language); public void SetGenerateConstructorFromMembersOptionsAddNullChecks(string language, bool value) - => _globalOptions.SetGlobalOption(new OptionKey(s_addNullChecks, language), value); + => _globalOptions.SetGlobalOption(s_addNullChecks, language, value); } } diff --git a/src/EditorFeatures/Core/Options/NavigationBarViewOptionsStorage.cs b/src/EditorFeatures/Core/Options/NavigationBarViewOptionsStorage.cs index 24d9f3fc65c87..76a6a3126a12e 100644 --- a/src/EditorFeatures/Core/Options/NavigationBarViewOptionsStorage.cs +++ b/src/EditorFeatures/Core/Options/NavigationBarViewOptionsStorage.cs @@ -8,8 +8,6 @@ namespace Microsoft.CodeAnalysis.Editor.Options; internal sealed class NavigationBarViewOptionsStorage { - private const string FeatureName = "NavigationBarOptions"; - public static readonly PerLanguageOption2 ShowNavigationBar = new( - FeatureName, "ShowNavigationBar", defaultValue: true, new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Dropdown Bar")); + "NavigationBarOptions_ShowNavigationBar", defaultValue: true); } diff --git a/src/EditorFeatures/Core/Options/SignatureHelpViewOptionsStorage.cs b/src/EditorFeatures/Core/Options/SignatureHelpViewOptionsStorage.cs index b887e3fbdbaf3..10817e454cd26 100644 --- a/src/EditorFeatures/Core/Options/SignatureHelpViewOptionsStorage.cs +++ b/src/EditorFeatures/Core/Options/SignatureHelpViewOptionsStorage.cs @@ -8,8 +8,6 @@ namespace Microsoft.CodeAnalysis.Editor.Options; internal sealed class SignatureHelpViewOptionsStorage { - private const string FeatureName = "SignatureHelpOptions"; - public static readonly PerLanguageOption2 ShowSignatureHelp = new( - FeatureName, "ShowSignatureHelp", defaultValue: true, new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Auto List Params")); + "SignatureHelpOptions_ShowSignatureHelp", defaultValue: true); } diff --git a/src/EditorFeatures/Core/Options/TextBufferOptionProviders.cs b/src/EditorFeatures/Core/Options/TextBufferOptionProviders.cs index 04d72a952b195..7cc04d25f085f 100644 --- a/src/EditorFeatures/Core/Options/TextBufferOptionProviders.cs +++ b/src/EditorFeatures/Core/Options/TextBufferOptionProviders.cs @@ -48,7 +48,7 @@ public static SyntaxFormattingOptions GetSyntaxFormattingOptions(this ITextBuffe private static SyntaxFormattingOptions GetSyntaxFormattingOptionsImpl(ITextBuffer textBuffer, IEditorOptions editorOptions, IIndentationManagerService indentationManager, IGlobalOptionService globalOptions, LanguageServices languageServices, bool explicitFormat) { - var configOptions = new EditorAnalyzerConfigOptions(editorOptions); + var configOptions = editorOptions.ToAnalyzerConfigOptions(); var fallbackOptions = globalOptions.GetSyntaxFormattingOptions(languageServices); var options = configOptions.GetSyntaxFormattingOptions(fallbackOptions, languageServices); var lineFormattingOptions = GetLineFormattingOptionsImpl(textBuffer, editorOptions, indentationManager, explicitFormat); @@ -72,7 +72,7 @@ public static IndentationOptions GetIndentationOptions(this ITextBuffer textBuff public static AddImportPlacementOptions GetAddImportPlacementOptions(this ITextBuffer textBuffer, EditorOptionsService optionsProvider, LanguageServices languageServices, bool allowInHiddenRegions) { var editorOptions = optionsProvider.Factory.GetOptions(textBuffer); - var configOptions = new EditorAnalyzerConfigOptions(editorOptions); + var configOptions = editorOptions.ToAnalyzerConfigOptions(); var fallbackOptions = optionsProvider.GlobalOptions.GetAddImportPlacementOptions(languageServices); return configOptions.GetAddImportPlacementOptions(allowInHiddenRegions, fallbackOptions, languageServices); } @@ -80,7 +80,7 @@ public static AddImportPlacementOptions GetAddImportPlacementOptions(this ITextB public static CodeCleanupOptions GetCodeCleanupOptions(this ITextBuffer textBuffer, EditorOptionsService optionsProvider, LanguageServices languageServices, bool explicitFormat, bool allowImportsInHiddenRegions) { var editorOptions = optionsProvider.Factory.GetOptions(textBuffer); - var configOptions = new EditorAnalyzerConfigOptions(editorOptions); + var configOptions = editorOptions.ToAnalyzerConfigOptions(); var fallbackOptions = optionsProvider.GlobalOptions.GetCodeCleanupOptions(languageServices); var options = configOptions.GetCodeCleanupOptions(allowImportsInHiddenRegions, fallbackOptions, languageServices); diff --git a/src/EditorFeatures/Core/ReferenceHighlighting/ReferenceHighlightingViewTaggerProvider.cs b/src/EditorFeatures/Core/ReferenceHighlighting/ReferenceHighlightingViewTaggerProvider.cs index cb4ed0d782d46..2681590141662 100644 --- a/src/EditorFeatures/Core/ReferenceHighlighting/ReferenceHighlightingViewTaggerProvider.cs +++ b/src/EditorFeatures/Core/ReferenceHighlighting/ReferenceHighlightingViewTaggerProvider.cs @@ -46,7 +46,7 @@ internal sealed partial class ReferenceHighlightingViewTaggerProvider : Asynchro protected override TaggerCaretChangeBehavior CaretChangeBehavior => TaggerCaretChangeBehavior.RemoveAllTagsOnCaretMoveOutsideOfTag; protected override TaggerTextChangeBehavior TextChangeBehavior => TaggerTextChangeBehavior.RemoveAllTags; - protected override ImmutableArray Options { get; } = ImmutableArray.Create(FeatureOnOffOptions.ReferenceHighlighting); + protected override ImmutableArray Options { get; } = ImmutableArray.Create(FeatureOnOffOptions.ReferenceHighlighting); [ImportingConstructor] [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] diff --git a/src/EditorFeatures/Core/Remote/RemoteHostOptions.cs b/src/EditorFeatures/Core/Remote/RemoteHostOptions.cs index d7d91e233388d..c4ac3c0fc7752 100644 --- a/src/EditorFeatures/Core/Remote/RemoteHostOptions.cs +++ b/src/EditorFeatures/Core/Remote/RemoteHostOptions.cs @@ -2,33 +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. -using System; -using System.Collections.Immutable; -using System.Composition; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Options.Providers; -using Microsoft.CodeAnalysis.Storage; namespace Microsoft.CodeAnalysis.Remote { internal sealed class RemoteHostOptions { - private const string LocalRegistryPath = @"Roslyn\Internal\OnOff\Features\"; - private const string FeatureName = "InternalFeatureOnOffOptions"; - // use 64bit OOP - public static readonly Option2 OOP64Bit = new( - FeatureName, nameof(OOP64Bit), defaultValue: true, - storageLocation: new LocalUserProfileStorageLocation(LocalRegistryPath + nameof(OOP64Bit))); + public static readonly Option2 OOP64Bit = new("InternalFeatureOnOffOptions_OOP64Bit", defaultValue: true); - public static readonly Option2 OOPServerGCFeatureFlag = new( - FeatureName, nameof(OOPServerGCFeatureFlag), defaultValue: false, - new FeatureFlagStorageLocation("Roslyn.OOPServerGC")); + public static readonly Option2 OOPServerGCFeatureFlag = new("InternalFeatureOnOffOptions_OOPServerGCFeatureFlag", defaultValue: false); // use coreclr host for OOP - public static readonly Option2 OOPCoreClrFeatureFlag = new( - FeatureName, nameof(OOPCoreClrFeatureFlag), defaultValue: false, - new FeatureFlagStorageLocation("Roslyn.ServiceHubCore")); + public static readonly Option2 OOPCoreClrFeatureFlag = new("InternalFeatureOnOffOptions_OOPCoreClrFeatureFlag", defaultValue: false); } } diff --git a/src/EditorFeatures/Core/Shared/Options/ComponentOnOffOptions.cs b/src/EditorFeatures/Core/Shared/Options/ComponentOnOffOptions.cs index ea6a7ae15209a..eaabc09e15d2e 100644 --- a/src/EditorFeatures/Core/Shared/Options/ComponentOnOffOptions.cs +++ b/src/EditorFeatures/Core/Shared/Options/ComponentOnOffOptions.cs @@ -2,12 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Collections.Immutable; -using System.Composition; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Options.Providers; namespace Microsoft.CodeAnalysis.Editor.Shared.Options { @@ -16,16 +11,8 @@ namespace Microsoft.CodeAnalysis.Editor.Shared.Options /// internal sealed class EditorComponentOnOffOptions { - private const string LocalRegistryPath = @"Roslyn\Internal\OnOff\Components\"; - private const string FeatureName = "EditorComponentOnOffOptions"; - - public static readonly Option2 Adornment = new(FeatureName, "Adornment", defaultValue: true, - storageLocation: new LocalUserProfileStorageLocation(LocalRegistryPath + "Adornment")); - - public static readonly Option2 Tagger = new(FeatureName, "Tagger", defaultValue: true, - storageLocation: new LocalUserProfileStorageLocation(LocalRegistryPath + "Tagger")); - - public static readonly Option2 CodeRefactorings = new(FeatureName, "CodeRefactorings", defaultValue: true, - storageLocation: new LocalUserProfileStorageLocation(LocalRegistryPath + "Code Refactorings")); + public static readonly Option2 Adornment = new("EditorComponentOnOffOptions_Adornment", defaultValue: true); + public static readonly Option2 Tagger = new("EditorComponentOnOffOptions_Tagger", defaultValue: true); + public static readonly Option2 CodeRefactorings = new("EditorComponentOnOffOptions_CodeRefactorings", defaultValue: true); } } diff --git a/src/EditorFeatures/Core/Shared/Options/FeatureOnOffOptions.cs b/src/EditorFeatures/Core/Shared/Options/FeatureOnOffOptions.cs index d6b62ab0819eb..71336cb73d259 100644 --- a/src/EditorFeatures/Core/Shared/Options/FeatureOnOffOptions.cs +++ b/src/EditorFeatures/Core/Shared/Options/FeatureOnOffOptions.cs @@ -2,49 +2,32 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Collections.Immutable; -using System.Composition; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Options.Providers; namespace Microsoft.CodeAnalysis.Editor.Shared.Options { internal sealed class FeatureOnOffOptions { - private const string FeatureName = "FeatureOnOffOptions"; - - public static readonly PerLanguageOption2 EndConstruct = new(FeatureName, "EndConstruct", defaultValue: true, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.AutoEndInsert")); + public static readonly PerLanguageOption2 EndConstruct = new("FeatureOnOffOptions_EndConstruct", defaultValue: true); // This value is only used by Visual Basic, and so is using the old serialization name that was used by VB. - public static readonly PerLanguageOption2 AutomaticInsertionOfAbstractOrInterfaceMembers = new(FeatureName, "AutomaticInsertionOfAbstractOrInterfaceMembers", defaultValue: true, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.AutoRequiredMemberInsert")); + public static readonly PerLanguageOption2 AutomaticInsertionOfAbstractOrInterfaceMembers = new("FeatureOnOffOptions_AutomaticInsertionOfAbstractOrInterfaceMembers", defaultValue: true); - public static readonly PerLanguageOption2 LineSeparator = new(FeatureName, "LineSeparator", defaultValue: false, - storageLocation: new RoamingProfileStorageLocation(language => language == LanguageNames.VisualBasic ? "TextEditor.%LANGUAGE%.Specific.DisplayLineSeparators" : "TextEditor.%LANGUAGE%.Specific.Line Separator")); + public static readonly PerLanguageOption2 LineSeparator = new("FeatureOnOffOptions_LineSeparator", defaultValue: false); - public static readonly PerLanguageOption2 Outlining = new(FeatureName, "Outlining", defaultValue: true, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.Outlining")); + public static readonly PerLanguageOption2 Outlining = new("FeatureOnOffOptions_Outlining", defaultValue: true); - public static readonly PerLanguageOption2 KeywordHighlighting = new(FeatureName, "KeywordHighlighting", defaultValue: true, - storageLocation: new RoamingProfileStorageLocation(language => language == LanguageNames.VisualBasic ? "TextEditor.%LANGUAGE%.Specific.EnableHighlightRelatedKeywords" : "TextEditor.%LANGUAGE%.Specific.Keyword Highlighting")); + public static readonly PerLanguageOption2 KeywordHighlighting = new("FeatureOnOffOptions_KeywordHighlighting", defaultValue: true); - public static readonly PerLanguageOption2 ReferenceHighlighting = new(FeatureName, "ReferenceHighlighting", defaultValue: true, - storageLocation: new RoamingProfileStorageLocation(language => language == LanguageNames.VisualBasic ? "TextEditor.%LANGUAGE%.Specific.EnableHighlightReferences" : "TextEditor.%LANGUAGE%.Specific.Reference Highlighting")); + public static readonly PerLanguageOption2 ReferenceHighlighting = new("FeatureOnOffOptions_ReferenceHighlighting", defaultValue: true); - public static readonly PerLanguageOption2 AutoInsertBlockCommentStartString = new(FeatureName, "AutoInsertBlockCommentStartString", defaultValue: true, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.Auto Insert Block Comment Start String")); + public static readonly PerLanguageOption2 AutoInsertBlockCommentStartString = new("FeatureOnOffOptions_AutoInsertBlockCommentStartString", defaultValue: true); - public static readonly PerLanguageOption2 PrettyListing = new(FeatureName, "PrettyListing", defaultValue: true, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.PrettyListing")); + public static readonly PerLanguageOption2 PrettyListing = new("FeatureOnOffOptions_PrettyListing", defaultValue: true); - public static readonly PerLanguageOption2 StringIdentation = new(FeatureName, "StringIdentation", defaultValue: true, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.StringIdentation")); + public static readonly PerLanguageOption2 StringIdentation = new("FeatureOnOffOptions_StringIdentation", defaultValue: true); - public static readonly PerLanguageOption2 RenameTrackingPreview = new(FeatureName, "RenameTrackingPreview", defaultValue: true, - storageLocation: new RoamingProfileStorageLocation(language => language == LanguageNames.VisualBasic ? "TextEditor.%LANGUAGE%.Specific.RenameTrackingPreview" : "TextEditor.%LANGUAGE%.Specific.Rename Tracking Preview")); + public static readonly PerLanguageOption2 RenameTrackingPreview = new("FeatureOnOffOptions_RenameTrackingPreview", defaultValue: true); /// /// This option is not currently used by Roslyn, but we might want to implement it in the @@ -52,7 +35,7 @@ internal sealed class FeatureOnOffOptions /// maintain any customized value for this setting, even through versions that have not /// implemented this feature yet. /// - public static readonly PerLanguageOption2 RenameTracking = new(FeatureName, "RenameTracking", defaultValue: true); + public static readonly PerLanguageOption2 RenameTracking = new("FeatureOnOffOptions_RenameTracking", defaultValue: true); /// /// This option is not currently used by Roslyn, but we might want to implement it in the @@ -60,12 +43,9 @@ internal sealed class FeatureOnOffOptions /// maintain any customized value for this setting, even through versions that have not /// implemented this feature yet. /// - public static readonly PerLanguageOption2 RefactoringVerification = new( - FeatureName, "RefactoringVerification", defaultValue: false); + public static readonly PerLanguageOption2 RefactoringVerification = new("FeatureOnOffOptions_RefactoringVerification", defaultValue: false); - public static readonly Option2 NavigateAsynchronously = new( - FeatureName, "NavigateAsynchronously", defaultValue: true, - storageLocation: new RoamingProfileStorageLocation("TextEditor.NavigateAsynchronously")); + public static readonly Option2 NavigateAsynchronously = new("FeatureOnOffOptions_NavigateAsynchronously", defaultValue: true); /// /// This option was previously "bool?" to accomodate different supported defaults @@ -73,44 +53,26 @@ internal sealed class FeatureOnOffOptions /// to on by default, so the storage location was changed to /// TextEditor.%LANGUAGE%.Specific.AddImportsOnPaste2 (note the 2 suffix). /// - public static readonly PerLanguageOption2 AddImportsOnPaste = new( - FeatureName, "AddImportsOnPaste", defaultValue: true, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.AddImportsOnPaste2")); + public static readonly PerLanguageOption2 AddImportsOnPaste = new("FeatureOnOffOptions_AddImportsOnPaste", defaultValue: true); - public static readonly Option2 OfferRemoveUnusedReferences = new( - FeatureName, "OfferRemoveUnusedReferences", defaultValue: true, - storageLocation: new RoamingProfileStorageLocation("TextEditor.OfferRemoveUnusedReferences")); + public static readonly Option2 OfferRemoveUnusedReferences = new("FeatureOnOffOptions_OfferRemoveUnusedReferences", defaultValue: true); - public static readonly Option2 OfferRemoveUnusedReferencesFeatureFlag = new( - FeatureName, "OfferRemoveUnusedReferencesFeatureFlag", defaultValue: false, - new FeatureFlagStorageLocation("Roslyn.RemoveUnusedReferences")); + public static readonly Option2 OfferRemoveUnusedReferencesFeatureFlag = new("FeatureOnOffOptions_OfferRemoveUnusedReferencesFeatureFlag", defaultValue: false); - public static readonly PerLanguageOption2 ShowInheritanceMargin = new( - FeatureName, "ShowInheritanceMargin", defaultValue: true, - new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ShowInheritanceMargin")); + public static readonly PerLanguageOption2 ShowInheritanceMargin = new("FeatureOnOffOptions_ShowInheritanceMargin", defaultValue: true); - public static readonly Option2 InheritanceMarginCombinedWithIndicatorMargin = new( - FeatureName, "InheritanceMarginCombinedWithIndicatorMargin", defaultValue: false, - new RoamingProfileStorageLocation("TextEditor.InheritanceMarginCombinedWithIndicatorMargin")); + public static readonly Option2 InheritanceMarginCombinedWithIndicatorMargin = new("FeatureOnOffOptions_InheritanceMarginCombinedWithIndicatorMargin", defaultValue: false); - public static readonly PerLanguageOption2 InheritanceMarginIncludeGlobalImports = new( - FeatureName, "InheritanceMarginIncludeGlobalImports", defaultValue: true, - new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.InheritanceMarginIncludeGlobalImports")); + public static readonly PerLanguageOption2 InheritanceMarginIncludeGlobalImports = new("FeatureOnOffOptions_InheritanceMarginIncludeGlobalImports", defaultValue: true); - public static readonly Option2 AutomaticallyCompleteStatementOnSemicolon = new( - FeatureName, "AutomaticallyCompleteStatementOnSemicolon", defaultValue: true, - storageLocation: new RoamingProfileStorageLocation("TextEditor.AutomaticallyCompleteStatementOnSemicolon")); + public static readonly Option2 AutomaticallyCompleteStatementOnSemicolon = new("FeatureOnOffOptions_AutomaticallyCompleteStatementOnSemicolon", defaultValue: true); - public static readonly PerLanguageOption2 AutomaticallyFixStringContentsOnPaste = new( - FeatureName, "AutomaticallyFixStringContentsOnPaste", defaultValue: true, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.AutomaticallyFixStringContentsOnPaste")); + public static readonly PerLanguageOption2 AutomaticallyFixStringContentsOnPaste = new("FeatureOnOffOptions_AutomaticallyFixStringContentsOnPaste", defaultValue: true); /// /// 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 /// - public static readonly Option2 SkipAnalyzersForImplicitlyTriggeredBuilds = new( - FeatureName, "SkipAnalyzersForImplicitlyTriggeredBuilds", defaultValue: true, - storageLocation: new RoamingProfileStorageLocation("TextEditor.SkipAnalyzersForImplicitlyTriggeredBuilds")); + public static readonly Option2 SkipAnalyzersForImplicitlyTriggeredBuilds = new("FeatureOnOffOptions_SkipAnalyzersForImplicitlyTriggeredBuilds", defaultValue: true); } } diff --git a/src/EditorFeatures/Core/Shared/Options/InternalFeatureOnOffOptions.cs b/src/EditorFeatures/Core/Shared/Options/InternalFeatureOnOffOptions.cs index 6c155b5490a5e..55afe651cd0b3 100644 --- a/src/EditorFeatures/Core/Shared/Options/InternalFeatureOnOffOptions.cs +++ b/src/EditorFeatures/Core/Shared/Options/InternalFeatureOnOffOptions.cs @@ -2,55 +2,23 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Collections.Immutable; -using System.Composition; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Options.Providers; -using Microsoft.CodeAnalysis.Storage; namespace Microsoft.CodeAnalysis.Editor.Shared.Options { internal sealed class InternalFeatureOnOffOptions { - private const string LocalRegistryPath = @"Roslyn\Internal\OnOff\Features\"; - private const string FeatureName = "InternalFeatureOnOffOptions"; - - public static readonly Option2 BraceMatching = new(FeatureName, "BraceMatching", defaultValue: true, - storageLocation: new LocalUserProfileStorageLocation(LocalRegistryPath + "Brace Matching")); - - public static readonly Option2 Classification = new(FeatureName, "Classification", defaultValue: true, - storageLocation: new LocalUserProfileStorageLocation(LocalRegistryPath + "Classification")); - - public static readonly Option2 SemanticColorizer = new(FeatureName, "SemanticColorizer", defaultValue: true, - storageLocation: new LocalUserProfileStorageLocation(LocalRegistryPath + "Semantic Colorizer")); - - public static readonly Option2 SyntacticColorizer = new(FeatureName, "SyntacticColorizer", defaultValue: true, - storageLocation: new LocalUserProfileStorageLocation(LocalRegistryPath + "Syntactic Colorizer")); - - public static readonly Option2 AutomaticLineEnder = new(FeatureName, "AutomaticLineEnder", defaultValue: true, - storageLocation: new LocalUserProfileStorageLocation(LocalRegistryPath + "Automatic Line Ender")); - - public static readonly Option2 SmartIndenter = new(FeatureName, "SmartIndenter", defaultValue: true, - storageLocation: new LocalUserProfileStorageLocation(LocalRegistryPath + "Smart Indenter")); - - public static readonly Option2 Squiggles = new(FeatureName, "Squiggles", defaultValue: true, - storageLocation: new LocalUserProfileStorageLocation(LocalRegistryPath + "Squiggles")); - - public static readonly Option2 FormatOnSave = new(FeatureName, "FormatOnSave", defaultValue: true, - storageLocation: new LocalUserProfileStorageLocation(LocalRegistryPath + "FormatOnSave")); - - public static readonly Option2 RenameTracking = new(FeatureName, "RenameTracking", defaultValue: true, - storageLocation: new LocalUserProfileStorageLocation(LocalRegistryPath + "Rename Tracking")); - - public static readonly Option2 EventHookup = new(FeatureName, "EventHookup", defaultValue: true, - storageLocation: new LocalUserProfileStorageLocation(LocalRegistryPath + "Event Hookup")); - - public static readonly Option2 Snippets = new(FeatureName, "Snippets", defaultValue: true, - storageLocation: new LocalUserProfileStorageLocation(LocalRegistryPath + "Snippets2")); - - public static readonly Option2 BackgroundAnalysisMemoryMonitor = new(FeatureName, "FullSolutionAnalysisMemoryMonitor", defaultValue: true, - storageLocation: new LocalUserProfileStorageLocation(LocalRegistryPath + "Full Solution Analysis Memory Monitor")); + public static readonly Option2 BraceMatching = new("InternalFeatureOnOffOptions_BraceMatching", defaultValue: true); + public static readonly Option2 Classification = new("InternalFeatureOnOffOptions_Classification", defaultValue: true); + public static readonly Option2 SemanticColorizer = new("InternalFeatureOnOffOptions_SemanticColorizer", defaultValue: true); + public static readonly Option2 SyntacticColorizer = new("InternalFeatureOnOffOptions_SyntacticColorizer", defaultValue: true); + public static readonly Option2 AutomaticLineEnder = new("InternalFeatureOnOffOptions_AutomaticLineEnder", defaultValue: true); + public static readonly Option2 SmartIndenter = new("InternalFeatureOnOffOptions_SmartIndenter", defaultValue: true); + public static readonly Option2 Squiggles = new("InternalFeatureOnOffOptions_Squiggles", defaultValue: true); + public static readonly Option2 FormatOnSave = new("InternalFeatureOnOffOptions_FormatOnSave", defaultValue: true); + public static readonly Option2 RenameTracking = new("InternalFeatureOnOffOptions_RenameTracking", defaultValue: true); + public static readonly Option2 EventHookup = new("InternalFeatureOnOffOptions_EventHookup", defaultValue: true); + public static readonly Option2 Snippets = new("InternalFeatureOnOffOptions_Snippets", defaultValue: true); + public static readonly Option2 BackgroundAnalysisMemoryMonitor = new("InternalFeatureOnOffOptions_FullSolutionAnalysisMemoryMonitor", defaultValue: true); } } diff --git a/src/EditorFeatures/Core/Shared/Preview/PreviewSolutionCrawlerRegistrationService.cs b/src/EditorFeatures/Core/Shared/Preview/PreviewSolutionCrawlerRegistrationService.cs index 55417f60feac4..739d664e23a6a 100644 --- a/src/EditorFeatures/Core/Shared/Preview/PreviewSolutionCrawlerRegistrationService.cs +++ b/src/EditorFeatures/Core/Shared/Preview/PreviewSolutionCrawlerRegistrationService.cs @@ -116,15 +116,25 @@ public void Unregister(Workspace workspace, bool blockingShutdown = false) private async Task UnregisterAsync(Workspace workspace) { Contract.ThrowIfFalse(workspace == _workspace); - Contract.ThrowIfNull(_analyzeTask); _source.Cancel(); - // wait for analyzer work to be finished - await _analyzeTask.ConfigureAwait(false); + try + { + var analyzeTask = _analyzeTask; + if (analyzeTask != null) + { + // wait for analyzer work to be finished + await analyzeTask.ConfigureAwait(false); + } + } + finally + { + _source.Dispose(); - // ask it to reset its stages for the given workspace - _owner._analyzerService.ShutdownAnalyzerFrom(_workspace); + // ask it to reset its stages for the given workspace + _owner._analyzerService.ShutdownAnalyzerFrom(_workspace); + } } public void AddAnalyzerProvider(IIncrementalAnalyzerProvider provider, IncrementalAnalyzerProviderMetadata metadata) diff --git a/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.OptionChangedEventSource.cs b/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.OptionChangedEventSource.cs index 608aa0d55916a..e0c63de3690d2 100644 --- a/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.OptionChangedEventSource.cs +++ b/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.OptionChangedEventSource.cs @@ -11,10 +11,10 @@ internal partial class TaggerEventSources { private sealed class GlobalOptionChangedEventSource : AbstractTaggerEventSource { - private readonly IOption _globalOption; + private readonly IOption2 _globalOption; private readonly IGlobalOptionService _globalOptions; - public GlobalOptionChangedEventSource(IGlobalOptionService globalOptions, IOption globalOption) + public GlobalOptionChangedEventSource(IGlobalOptionService globalOptions, IOption2 globalOption) { _globalOptions = globalOptions; _globalOption = globalOption; diff --git a/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.cs b/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.cs index b545c25e30386..62e1766046caa 100644 --- a/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.cs +++ b/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.cs @@ -47,7 +47,7 @@ public static ITaggerEventSource OnSelectionChanged(ITextView textView) public static ITaggerEventSource OnReadOnlyRegionsChanged(ITextBuffer subjectBuffer) => new ReadOnlyRegionsChangedEventSource(subjectBuffer); - public static ITaggerEventSource OnGlobalOptionChanged(IGlobalOptionService globalOptions, IOption globalOption) + public static ITaggerEventSource OnGlobalOptionChanged(IGlobalOptionService globalOptions, IOption2 globalOption) => new GlobalOptionChangedEventSource(globalOptions, globalOption); public static ITaggerEventSource OnDiagnosticsChanged(ITextBuffer subjectBuffer, IDiagnosticService service) diff --git a/src/EditorFeatures/Core/SplitComment/SplitCommentOptions.cs b/src/EditorFeatures/Core/SplitComment/SplitCommentOptions.cs index dd8d89b5be12c..5e591d0fd3cfb 100644 --- a/src/EditorFeatures/Core/SplitComment/SplitCommentOptions.cs +++ b/src/EditorFeatures/Core/SplitComment/SplitCommentOptions.cs @@ -2,19 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Collections.Immutable; -using System.Composition; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Options.Providers; namespace Microsoft.CodeAnalysis.Editor.Implementation.SplitComment { internal sealed class SplitCommentOptions { public static PerLanguageOption2 Enabled = - new PerLanguageOption2(nameof(SplitCommentOptions), nameof(Enabled), defaultValue: true, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.SplitComments")); + new PerLanguageOption2("SplitCommentOptions_Enabled", defaultValue: true); } } diff --git a/src/EditorFeatures/Core/Suggestions/SuggestionsOptions.cs b/src/EditorFeatures/Core/Suggestions/SuggestionsOptions.cs index dde68b6524996..6617121b19f02 100644 --- a/src/EditorFeatures/Core/Suggestions/SuggestionsOptions.cs +++ b/src/EditorFeatures/Core/Suggestions/SuggestionsOptions.cs @@ -2,23 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Collections.Immutable; -using System.Composition; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Options.Providers; namespace Microsoft.CodeAnalysis.Editor.Implementation.Suggestions { internal sealed class SuggestionsOptions { - private const string FeatureName = "SuggestionsOptions"; - - public static readonly Option2 Asynchronous = new(FeatureName, nameof(Asynchronous), defaultValue: null, - new RoamingProfileStorageLocation("TextEditor.Specific.Suggestions.Asynchronous4")); - - public static readonly Option2 AsynchronousQuickActionsDisableFeatureFlag = new(FeatureName, nameof(AsynchronousQuickActionsDisableFeatureFlag), defaultValue: false, - new FeatureFlagStorageLocation("Roslyn.AsynchronousQuickActionsDisable2")); + public static readonly Option2 Asynchronous = new("SuggestionsOptions_Asynchronous", defaultValue: null); + public static readonly Option2 AsynchronousQuickActionsDisableFeatureFlag = new("SuggestionsOptions_AsynchronousQuickActionsDisableFeatureFlag", defaultValue: false); } } diff --git a/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.cs b/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.cs index 602d0c4837394..c951044d880d8 100644 --- a/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.cs +++ b/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.cs @@ -71,13 +71,13 @@ internal abstract partial class AbstractAsynchronousTaggerProvider where T /// An empty enumerable can be returned to indicate that this tagger should run unconditionally. /// /// All values must either be an or a . - protected virtual ImmutableArray Options => ImmutableArray.Empty; + protected virtual ImmutableArray Options => ImmutableArray.Empty; /// /// Options controlling the feature that should be used to determine if the feature should recompute tags. /// These generally correspond to user facing options to change how a feature behaves if it is running. /// - protected virtual ImmutableArray FeatureOptions => ImmutableArray.Empty; + protected virtual ImmutableArray FeatureOptions => ImmutableArray.Empty; protected virtual bool ComputeInitialTagsSynchronously(ITextBuffer subjectBuffer) => false; diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/CodeFixVerifierHelper.cs b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/CodeFixVerifierHelper.cs index 26c9a0d630ca9..4dcb032e8e271 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/CodeFixVerifierHelper.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/CodeFixVerifierHelper.cs @@ -96,20 +96,17 @@ private static void VerifyMessageHelpLinkUri(DiagnosticAnalyzer analyzer) public static string? GetEditorConfigText(this OptionsCollection options) { - var (text, _) = ConvertOptionsToAnalyzerConfig(options.DefaultExtension, explicitEditorConfig: string.Empty, options); + var text = ConvertOptionsToAnalyzerConfig(options.DefaultExtension, explicitEditorConfig: string.Empty, options); return text?.ToString(); } - public static (SourceText? analyzerConfig, IEnumerable> options) ConvertOptionsToAnalyzerConfig(string defaultFileExtension, string? explicitEditorConfig, OptionsCollection options) + public static SourceText? ConvertOptionsToAnalyzerConfig(string defaultFileExtension, string? explicitEditorConfig, OptionsCollection options) { if (options.Count == 0) { - var result = explicitEditorConfig is object ? SourceText.From(explicitEditorConfig, Encoding.UTF8) : null; - return (result, options); + return explicitEditorConfig is object ? SourceText.From(explicitEditorConfig, Encoding.UTF8) : null; } - var remainingOptions = new List>(); - var analyzerConfig = new StringBuilder(); if (explicitEditorConfig is object) { @@ -125,24 +122,18 @@ public static (SourceText? analyzerConfig, IEnumerable().FirstOrDefault(); - if (editorConfigStorageLocation is null) - { - remainingOptions.Add(KeyValuePairUtil.Create(optionKey, value)); - continue; - } - - var line = editorConfigStorageLocation.GetEditorConfigString(value); - analyzerConfig.AppendLine(line); + analyzerConfig.AppendLine($"{optionKey.Option.Definition.ConfigName} = {optionKey.Option.Definition.Serializer.Serialize(value)}"); } - return (SourceText.From(analyzerConfig.ToString(), Encoding.UTF8), remainingOptions); + return SourceText.From(analyzerConfig.ToString(), Encoding.UTF8); } } } diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/SharedVerifierState.cs b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/SharedVerifierState.cs index 4a9d69196d525..e70dc8060dcb1 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/SharedVerifierState.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/SharedVerifierState.cs @@ -56,7 +56,7 @@ internal IdeAnalyzerOptions GetIdeAnalyzerOptions(Project project) #endif internal void Apply() { - var (analyzerConfigSource, remainingOptions) = CodeFixVerifierHelper.ConvertOptionsToAnalyzerConfig(_defaultFileExt, EditorConfig, Options); + var analyzerConfigSource = CodeFixVerifierHelper.ConvertOptionsToAnalyzerConfig(_defaultFileExt, EditorConfig, Options); if (analyzerConfigSource is not null) { if (_analyzerConfigIndex is null) @@ -76,34 +76,7 @@ internal void Apply() } var solutionTransformIndex = _remainingOptionsSolutionTransform is not null ? _test.SolutionTransforms.IndexOf(_remainingOptionsSolutionTransform) : -1; - if (remainingOptions is not null) - { - // Generate a new solution transform - _remainingOptionsSolutionTransform = (solution, projectId) => - { -#if !CODE_STYLE - var options = solution.Options; - foreach (var (key, value) in remainingOptions) - { - options = options.WithChangedOption(key, value); - } - - solution = solution.WithOptions(options); -#endif - - return solution; - }; - - if (solutionTransformIndex < 0) - { - _test.SolutionTransforms.Add(_remainingOptionsSolutionTransform); - } - else - { - _test.SolutionTransforms[solutionTransformIndex] = _remainingOptionsSolutionTransform; - } - } - else if (_remainingOptionsSolutionTransform is not null) + if (_remainingOptionsSolutionTransform is not null) { _test.SolutionTransforms.Remove(_remainingOptionsSolutionTransform); _remainingOptionsSolutionTransform = null; diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/NamingStyles/NamingStylesTestOptionSets.cs b/src/EditorFeatures/DiagnosticsTestUtilities/NamingStyles/NamingStylesTestOptionSets.cs index 498e8bd601549..3800ee03edb0c 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/NamingStyles/NamingStylesTestOptionSets.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/NamingStyles/NamingStylesTestOptionSets.cs @@ -25,7 +25,7 @@ internal sealed class NamingStylesTestOptionSets public NamingStylesTestOptionSets(string languageName) { _languageName = languageName; - _optionKey = NamingStyleOptions.GetNamingPreferencesOptionKey(languageName); + _optionKey = new OptionKey2(NamingStyleOptions.NamingPreferences, languageName); } public OptionKey2 OptionKey => _optionKey; diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/SplitComments/AbstractSplitCommentCommandHandlerTests.cs b/src/EditorFeatures/DiagnosticsTestUtilities/SplitComments/AbstractSplitCommentCommandHandlerTests.cs index eb72a8da16e09..db6086559579e 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/SplitComments/AbstractSplitCommentCommandHandlerTests.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/SplitComments/AbstractSplitCommentCommandHandlerTests.cs @@ -55,8 +55,8 @@ private void TestWorker( var globalOptions = workspace.GlobalOptions; var language = workspace.Projects.Single().Language; - globalOptions.SetGlobalOption(new OptionKey(SplitCommentOptions.Enabled, language), enabled); - globalOptions.SetGlobalOption(new OptionKey(FormattingOptions2.UseTabs, language), useTabs); + globalOptions.SetGlobalOption(SplitCommentOptions.Enabled, language, enabled); + globalOptions.SetGlobalOption(FormattingOptions2.UseTabs, language, useTabs); var document = workspace.Documents.Single(); var view = document.GetTextView(); diff --git a/src/EditorFeatures/Test/Completion/CompletionServiceTests.cs b/src/EditorFeatures/Test/Completion/CompletionServiceTests.cs index c6b92f3d7317a..09c6dcf78df0d 100644 --- a/src/EditorFeatures/Test/Completion/CompletionServiceTests.cs +++ b/src/EditorFeatures/Test/Completion/CompletionServiceTests.cs @@ -46,7 +46,7 @@ void Method() { var document = project.Documents.Single(); var caretPosition = workspace.DocumentWithCursor.CursorPosition ?? throw new InvalidOperationException(); - var completions = await completionService.GetCompletionsAsync(document, caretPosition, CompletionOptions.Default, OptionValueSet.Empty); + var completions = await completionService.GetCompletionsAsync(document, caretPosition, CompletionOptions.Default, OptionSet.Empty); // NuGet providers are not included until it's loaded and cached, this is to avoid potential delays, especially on UI thread. Assert.Empty(completions.ItemsList); @@ -55,7 +55,7 @@ void Method() { var waiter = workspace.ExportProvider.GetExportedValue().GetWaiter(FeatureAttribute.CompletionSet); await waiter.ExpeditedWaitAsync(); - completions = await completionService.GetCompletionsAsync(document, caretPosition, CompletionOptions.Default, OptionValueSet.Empty); + completions = await completionService.GetCompletionsAsync(document, caretPosition, CompletionOptions.Default, OptionSet.Empty); Assert.NotEmpty(completions.ItemsList); diff --git a/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs b/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs index b47a4064b3672..82a5eb7b74b49 100644 --- a/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs +++ b/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs @@ -102,7 +102,7 @@ public async Task TestHasSuccessfullyLoadedBeingFalseFSAOn() var analyzerReference = new AnalyzerImageReference(ImmutableArray.Create(new Analyzer())); var globalOptions = GetGlobalOptions(workspace); - globalOptions.SetGlobalOption(new OptionKey(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp), BackgroundAnalysisScope.FullSolution); + globalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp, BackgroundAnalysisScope.FullSolution); workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences(new[] { analyzerReference })); var document = GetDocumentFromIncompleteProject(workspace); @@ -151,7 +151,7 @@ public async Task TestHasSuccessfullyLoadedBeingFalseWithCompilerAnalyzerFSAOn() var analyzerReference = new AnalyzerImageReference(ImmutableArray.Create(new CSharpCompilerDiagnosticAnalyzer())); var globalOptions = GetGlobalOptions(workspace); - globalOptions.SetGlobalOption(new OptionKey(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp), BackgroundAnalysisScope.FullSolution); + globalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp, BackgroundAnalysisScope.FullSolution); workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences(new[] { analyzerReference })); @@ -170,7 +170,7 @@ public async Task TestDisabledByDefaultAnalyzerEnabledWithEditorConfig(bool enab var analyzerReference = new AnalyzerImageReference(ImmutableArray.Create(new DisabledByDefaultAnalyzer())); var globalOptions = GetGlobalOptions(workspace); - globalOptions.SetGlobalOption(new OptionKey(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp), BackgroundAnalysisScope.FullSolution); + globalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp, BackgroundAnalysisScope.FullSolution); workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences(new[] { analyzerReference })); @@ -469,7 +469,7 @@ public async Task TestHostAnalyzerErrorNotLeaking() new LeakDocumentAnalyzer(), new LeakProjectAnalyzer())); var globalOptions = GetGlobalOptions(workspace); - globalOptions.SetGlobalOption(new OptionKey(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp), BackgroundAnalysisScope.FullSolution); + globalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp, BackgroundAnalysisScope.FullSolution); workspace.TryApplyChanges(solution.WithAnalyzerReferences(new[] { analyzerReference })); @@ -564,7 +564,7 @@ private static AdhocWorkspace CreateWorkspaceWithProjectAndAnalyzer(DiagnosticAn var workspace = CreateWorkspace(); var globalOptions = GetGlobalOptions(workspace); - globalOptions.SetGlobalOption(new OptionKey(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp), BackgroundAnalysisScope.FullSolution); + globalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp, BackgroundAnalysisScope.FullSolution); var projectId = ProjectId.CreateNewId(); var solution = workspace.CurrentSolution; @@ -627,7 +627,7 @@ internal async Task TestAdditionalFileAnalyzer(bool registerFromInitialize, bool using var workspace = CreateWorkspace(); var globalOptions = GetGlobalOptions(workspace); - globalOptions.SetGlobalOption(new OptionKey(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp), analysisScope); + globalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp, analysisScope); var projectInfo = ProjectInfo.Create(ProjectId.CreateNewId(), VersionStamp.Create(), "CSharpProject", "CSharpProject", LanguageNames.CSharp); var project = workspace.AddProject(projectInfo); @@ -751,7 +751,7 @@ internal async Task TestDiagnosticSuppressor(bool includeAnalyzer, bool includeS using var workspace = TestWorkspace.CreateCSharp("class A {}", composition: s_editorFeaturesCompositionWithMockDiagnosticUpdateSourceRegistrationService.AddParts(typeof(TestDocumentTrackingService))); - workspace.GlobalOptions.SetGlobalOption(new OptionKey(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp), analysisScope); + workspace.GlobalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp, analysisScope); workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences(new[] { analyzerReference })); @@ -876,11 +876,11 @@ void M() using var workspace = new TestWorkspace(composition); - workspace.GlobalOptions.SetGlobalOption(new OptionKey(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp), analysisScope); - workspace.GlobalOptions.SetGlobalOption(new OptionKey(SolutionCrawlerOptionsStorage.EnableDiagnosticsInSourceGeneratedFiles), isSourceGenerated); + workspace.GlobalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp, analysisScope); + workspace.GlobalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.EnableDiagnosticsInSourceGeneratedFiles, isSourceGenerated); var compilerDiagnosticsScope = analysisScope.ToEquivalentCompilerDiagnosticsScope(); - workspace.GlobalOptions.SetGlobalOption(new OptionKey(SolutionCrawlerOptionsStorage.CompilerDiagnosticsScopeOption, LanguageNames.CSharp), compilerDiagnosticsScope); + workspace.GlobalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.CompilerDiagnosticsScopeOption, LanguageNames.CSharp, compilerDiagnosticsScope); workspace.InitializeDocuments(TestWorkspace.CreateWorkspaceElement(LanguageNames.CSharp, files: files, sourceGeneratedFiles: sourceGeneratedFiles), openDocuments: false); workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences(new[] { analyzerReference })); @@ -1152,7 +1152,7 @@ internal async Task TestGeneratorProducedDiagnostics(bool fullSolutionAnalysis) if (fullSolutionAnalysis) { - globalOptions.SetGlobalOption(new OptionKey(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp), BackgroundAnalysisScope.FullSolution); + globalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp, BackgroundAnalysisScope.FullSolution); } else { diff --git a/src/EditorFeatures/Test/Diagnostics/DiagnosticsClassificationTaggerProviderTests.cs b/src/EditorFeatures/Test/Diagnostics/DiagnosticsClassificationTaggerProviderTests.cs index fada59b76e859..0e5013cef7257 100644 --- a/src/EditorFeatures/Test/Diagnostics/DiagnosticsClassificationTaggerProviderTests.cs +++ b/src/EditorFeatures/Test/Diagnostics/DiagnosticsClassificationTaggerProviderTests.cs @@ -134,7 +134,7 @@ public async Task Test_FadingOptions(string diagnosticId, bool fadingOptionValue // Set fading option var fadingOption = GetFadingOptionForDiagnostic(diagnosticId); - workspace.GlobalOptions.SetGlobalOption(new OptionKey(fadingOption, LanguageNames.CSharp), fadingOptionValue); + workspace.GlobalOptions.SetGlobalOption(fadingOption, LanguageNames.CSharp, fadingOptionValue); // Add mapping from diagnostic ID to fading option IDEDiagnosticIdToOptionMappingHelper.AddFadingOptionMapping(diagnosticId, fadingOption); diff --git a/src/EditorFeatures/Test/Diagnostics/DiagnosticsSquiggleTaggerProviderTests.cs b/src/EditorFeatures/Test/Diagnostics/DiagnosticsSquiggleTaggerProviderTests.cs index 64c82ca8f9cf0..055fee910a8e5 100644 --- a/src/EditorFeatures/Test/Diagnostics/DiagnosticsSquiggleTaggerProviderTests.cs +++ b/src/EditorFeatures/Test/Diagnostics/DiagnosticsSquiggleTaggerProviderTests.cs @@ -46,8 +46,7 @@ public async Task Test_TagSourceDiffer(bool pull) }; using var workspace = TestWorkspace.CreateCSharp(new string[] { "class A { }", "class E { }" }, parseOptions: CSharpParseOptions.Default); - workspace.GlobalOptions.SetGlobalOption( - new OptionKey(DiagnosticTaggingOptions.PullDiagnosticTagging), pull); + workspace.GlobalOptions.SetGlobalOption(DiagnosticTaggingOptions.PullDiagnosticTagging, pull); using var wrapper = new DiagnosticTaggerWrapper(workspace, analyzerMap); @@ -79,8 +78,7 @@ public async Task Test_TagSourceDiffer(bool pull) public async Task MultipleTaggersAndDispose(bool pull) { using var workspace = TestWorkspace.CreateCSharp(new string[] { "class A {" }, parseOptions: CSharpParseOptions.Default); - workspace.GlobalOptions.SetGlobalOption( - new OptionKey(DiagnosticTaggingOptions.PullDiagnosticTagging), pull); + workspace.GlobalOptions.SetGlobalOption(DiagnosticTaggingOptions.PullDiagnosticTagging, pull); using var wrapper = new DiagnosticTaggerWrapper(workspace); @@ -104,8 +102,7 @@ public async Task MultipleTaggersAndDispose(bool pull) public async Task TaggerProviderCreatedAfterInitialDiagnosticsReported(bool pull) { using var workspace = TestWorkspace.CreateCSharp(new string[] { "class C {" }, parseOptions: CSharpParseOptions.Default); - workspace.GlobalOptions.SetGlobalOption( - new OptionKey(DiagnosticTaggingOptions.PullDiagnosticTagging), pull); + workspace.GlobalOptions.SetGlobalOption(DiagnosticTaggingOptions.PullDiagnosticTagging, pull); using var wrapper = new DiagnosticTaggerWrapper(workspace, analyzerMap: null, createTaggerProvider: false); // First, make sure all diagnostics have been reported. diff --git a/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs b/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs index 0e85703a11b2d..bced24f87900d 100644 --- a/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs +++ b/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs @@ -17,6 +17,7 @@ using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; +using Roslyn.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics.ConfigureSeverityLevel @@ -104,7 +105,6 @@ private static Dictionary GetExpectedMap(string expected, out st private static void VerifyConfigureSeverityCore(string expected, string languageName) { using var workspace = new TestWorkspace(); - var optionSet = workspace.Options; var diagnosticIdAndOptions = GetIDEDiagnosticIdsAndOptions(languageName); var expectedMap = GetExpectedMap(expected, out var expectedLines); @@ -661,479 +661,216 @@ public void VisualBasic_VerifyIDEDiagnosticSeveritiesAreConfigurable() VerifyConfigureSeverityCore(expected, LanguageNames.VisualBasic); } - private static void VerifyConfigureCodeStyleOptionsCore(string expected, string languageName) + private static void VerifyConfigureCodeStyleOptionsCore((string diagnosticId, string optionName, string optionValue)[] expected, string languageName) { using var workspace = new TestWorkspace(); - var optionSet = workspace.Options; var diagnosticIdAndOptions = GetIDEDiagnosticIdsAndOptions(languageName); - var expectedMap = GetExpectedMap(expected, out var expectedLines); + var expectedMap = expected.ToDictionary(entry => (entry.diagnosticId, entry.optionName), entry => entry.optionValue); - var baseline = new StringBuilder(); + var baseline = new List<(string diagnosticId, string optionName, string optionValue)>(); foreach (var (diagnosticId, options) in diagnosticIdAndOptions) { var hasEditorConfigCodeStyleOptions = false; - foreach (var option in options.OrderBy(o => o.Name)) + foreach (var option in options.OrderBy(o => o.Definition.ConfigName)) { - var editorConfigLocation = option.StorageLocations.OfType().FirstOrDefault(); - if (editorConfigLocation == null) - { - continue; - } - - var optionKey = new OptionKey(option, option.IsPerLanguage ? languageName : null); - var editorConfigString = editorConfigLocation.GetEditorConfigString(optionKey, optionSet); - - ProcessDiagnosticIdAndOption(diagnosticId, option, editorConfigString); + ProcessDiagnosticIdAndOption(diagnosticId, option); hasEditorConfigCodeStyleOptions = true; } if (!hasEditorConfigCodeStyleOptions) { - ProcessDiagnosticIdAndOption(diagnosticId, optionOpt: null, editorConfigString: "No editorconfig based code style option"); + ProcessDiagnosticIdAndOption(diagnosticId, option: null); } } - if (expectedLines.Length == 0) + if (expected.IsEmpty()) { - Assert.False(true, $"Test Baseline:{baseline}"); + Assert.False(true, + "Test Baseline:" + + Environment.NewLine + + string.Join(Environment.NewLine, baseline.Select(Inspect))); } if (expectedMap.Count > 0) { - var extraEntitiesBuilder = new StringBuilder(); - foreach (var kvp in expectedMap.OrderBy(kvp => kvp.Key)) + var extraEntitiesBuilder = new List<(string diagnosticId, string optionName, string optionValue)>(); + foreach (var entry in expectedMap.OrderBy(kvp => kvp.Key)) { - extraEntitiesBuilder.AppendLine(); - extraEntitiesBuilder.AppendLine(kvp.Key); - extraEntitiesBuilder.AppendLine(kvp.Value); + extraEntitiesBuilder.Add((entry.Key.diagnosticId, entry.Key.optionName, entry.Value)); } - Assert.False(true, $@"Unexpected entries:{extraEntitiesBuilder.ToString()}"); + Assert.False(true, + "Unexpected entries:" + + Environment.NewLine + + string.Join(Environment.NewLine, extraEntitiesBuilder.Select(Inspect))); } + static string Inspect((string diagnosticId, string optionName, string optionValue) item) + => @$"(""{item.diagnosticId}"", {(item.optionName != null ? '"' + item.optionName + '"' : "null")}, {(item.optionValue != null ? '"' + item.optionValue + '"' : "null")})"; + return; // Local functions - void ProcessDiagnosticIdAndOption(string diagnosticId, IOption optionOpt, string editorConfigString) + void ProcessDiagnosticIdAndOption(string diagnosticId, IOption2 option) { - // Verify we have an entry for { diagnosticId, optionName } - var diagnosticIdString = $"# {diagnosticId}"; - if (optionOpt != null) - { - diagnosticIdString += $", {optionOpt.Name}"; - } + var optionName = option?.Definition.ConfigName; + var optionValue = option?.Definition.Serializer.Serialize(option.DefaultValue); - if (expectedLines.Length == 0) + // Verify we have an entry for { diagnosticId, optionName } + if (expected.IsEmpty()) { // Executing test to generate baseline - baseline.AppendLine(); - baseline.AppendLine(diagnosticIdString); - baseline.AppendLine(editorConfigString); + baseline.Add((diagnosticId, optionName, optionValue)); return; } - if (!expectedMap.TryGetValue(diagnosticIdString, out var expectedValue)) + if (!expectedMap.TryGetValue((diagnosticId, optionName), out var expectedValue)) { - Assert.False(true, $@"Missing entry: - -{diagnosticIdString} -{editorConfigString} -"); + Assert.False(true, $@"Missing entry: {diagnosticId}, {optionName}, {optionValue}"); } // Verify entries match for diagnosticId - if (expectedValue != editorConfigString) + if (expectedValue != optionValue) { - Assert.False(true, $@"Mismatch for '{diagnosticId}' -Expected: {expectedValue} -Actual: {editorConfigString} -"); + Assert.False(true, $@"Mismatch for: {diagnosticId}, {optionName}, {optionValue}"); } - expectedMap.Remove(diagnosticIdString); + expectedMap.Remove((diagnosticId, optionName)); } } [Fact] public void CSharp_VerifyIDECodeStyleOptionsAreConfigurable() { - var expected = @" -# IDE0001 -No editorconfig based code style option - -# IDE0002 -No editorconfig based code style option - -# IDE0003, QualifyEventAccess -dotnet_style_qualification_for_event = false - -# IDE0003, QualifyFieldAccess -dotnet_style_qualification_for_field = false - -# IDE0003, QualifyMethodAccess -dotnet_style_qualification_for_method = false - -# IDE0003, QualifyPropertyAccess -dotnet_style_qualification_for_property = false - -# IDE0004 -No editorconfig based code style option - -# IDE0005 -No editorconfig based code style option - -# IDE0007, VarElsewhere -csharp_style_var_elsewhere = false - -# IDE0007, VarForBuiltInTypes -csharp_style_var_for_built_in_types = false - -# IDE0007, VarWhenTypeIsApparent -csharp_style_var_when_type_is_apparent = false - -# IDE0008, VarElsewhere -csharp_style_var_elsewhere = false - -# IDE0008, VarForBuiltInTypes -csharp_style_var_for_built_in_types = false - -# IDE0008, VarWhenTypeIsApparent -csharp_style_var_when_type_is_apparent = false - -# IDE0009, QualifyEventAccess -dotnet_style_qualification_for_event = false - -# IDE0009, QualifyFieldAccess -dotnet_style_qualification_for_field = false - -# IDE0009, QualifyMethodAccess -dotnet_style_qualification_for_method = false - -# IDE0009, QualifyPropertyAccess -dotnet_style_qualification_for_property = false - -# IDE0010 -No editorconfig based code style option - -# IDE0011, PreferBraces -csharp_prefer_braces = true - -# IDE0016, PreferThrowExpression -csharp_style_throw_expression = true - -# IDE0017, PreferObjectInitializer -dotnet_style_object_initializer = true - -# IDE0018, PreferInlinedVariableDeclaration -csharp_style_inlined_variable_declaration = true - -# IDE0019, PreferPatternMatchingOverAsWithNullCheck -csharp_style_pattern_matching_over_as_with_null_check = true - -# IDE0020, PreferPatternMatchingOverIsWithCastCheck -csharp_style_pattern_matching_over_is_with_cast_check = true - -# IDE0021, PreferExpressionBodiedConstructors -csharp_style_expression_bodied_constructors = false - -# IDE0022, PreferExpressionBodiedMethods -csharp_style_expression_bodied_methods = false - -# IDE0023, PreferExpressionBodiedOperators -csharp_style_expression_bodied_operators = false - -# IDE0024, PreferExpressionBodiedOperators -csharp_style_expression_bodied_operators = false - -# IDE0025, PreferExpressionBodiedProperties -csharp_style_expression_bodied_properties = true - -# IDE0026, PreferExpressionBodiedIndexers -csharp_style_expression_bodied_indexers = true - -# IDE0027, PreferExpressionBodiedAccessors -csharp_style_expression_bodied_accessors = true - -# IDE0028, PreferCollectionInitializer -dotnet_style_collection_initializer = true - -# IDE0029, PreferCoalesceExpression -dotnet_style_coalesce_expression = true - -# IDE0030, PreferCoalesceExpression -dotnet_style_coalesce_expression = true - -# IDE0031, PreferNullPropagation -dotnet_style_null_propagation = true - -# IDE0032, PreferAutoProperties -dotnet_style_prefer_auto_properties = true - -# IDE0033, PreferExplicitTupleNames -dotnet_style_explicit_tuple_names = true - -# IDE0034, PreferSimpleDefaultExpression -csharp_prefer_simple_default_expression = true - -# IDE0035 -No editorconfig based code style option - -# IDE0036, PreferredModifierOrder -csharp_preferred_modifier_order = public,private,protected,internal,file,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async - -# IDE0037, PreferInferredTupleNames -dotnet_style_prefer_inferred_tuple_names = true - -# IDE0037, PreferInferredAnonymousTypeMemberNames -dotnet_style_prefer_inferred_anonymous_type_member_names = true - -# IDE0038, PreferPatternMatchingOverIsWithCastCheck -csharp_style_pattern_matching_over_is_with_cast_check = true - -# IDE0039, PreferLocalOverAnonymousFunction -csharp_style_prefer_local_over_anonymous_function = true - -# IDE0040, RequireAccessibilityModifiers -dotnet_style_require_accessibility_modifiers = for_non_interface_members - -# IDE0041, PreferIsNullCheckOverReferenceEqualityMethod -dotnet_style_prefer_is_null_check_over_reference_equality_method = true - -# IDE0042, PreferDeconstructedVariableDeclaration -csharp_style_deconstructed_variable_declaration = true - -# IDE0043 -No editorconfig based code style option - -# IDE0044, PreferReadonly -dotnet_style_readonly_field = true - -# IDE0045, PreferConditionalExpressionOverAssignment -dotnet_style_prefer_conditional_expression_over_assignment = true - -# IDE0046, PreferConditionalExpressionOverReturn -dotnet_style_prefer_conditional_expression_over_return = true - -# IDE0047, ArithmeticBinaryParentheses -dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity - -# IDE0047, OtherBinaryParentheses -dotnet_style_parentheses_in_other_binary_operators = always_for_clarity - -# IDE0047, OtherParentheses -dotnet_style_parentheses_in_other_operators = never_if_unnecessary - -# IDE0047, RelationalBinaryParentheses -dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity - -# IDE0048, ArithmeticBinaryParentheses -dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity - -# IDE0048, OtherBinaryParentheses -dotnet_style_parentheses_in_other_binary_operators = always_for_clarity - -# IDE0048, OtherParentheses -dotnet_style_parentheses_in_other_operators = never_if_unnecessary - -# IDE0048, RelationalBinaryParentheses -dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity - -# IDE0049, PreferIntrinsicPredefinedTypeKeywordInDeclaration -dotnet_style_predefined_type_for_locals_parameters_members = true - -# IDE0049, PreferIntrinsicPredefinedTypeKeywordInMemberAccess -dotnet_style_predefined_type_for_member_access = true - -# IDE0051 -No editorconfig based code style option - -# IDE0052 -No editorconfig based code style option - -# IDE0053, PreferExpressionBodiedLambdas -csharp_style_expression_bodied_lambdas = true - -# IDE0054, PreferCompoundAssignment -dotnet_style_prefer_compound_assignment = true - -# IDE0055 -No editorconfig based code style option - -# IDE0056, PreferIndexOperator -csharp_style_prefer_index_operator = true - -# IDE0057, PreferRangeOperator -csharp_style_prefer_range_operator = true - -# IDE0058, UnusedValueExpressionStatement -csharp_style_unused_value_expression_statement_preference = discard_variable - -# IDE0059, UnusedValueAssignment -csharp_style_unused_value_assignment_preference = discard_variable - -# IDE0060, UnusedParameters -dotnet_code_quality_unused_parameters = all - -# IDE0061, PreferExpressionBodiedLocalFunctions -csharp_style_expression_bodied_local_functions = false - -# IDE0062, PreferStaticLocalFunction -csharp_prefer_static_local_function = true - -# IDE0063, PreferSimpleUsingStatement -csharp_prefer_simple_using_statement = true - -# IDE0064 -No editorconfig based code style option - -# IDE0065, PreferredUsingDirectivePlacement -csharp_using_directive_placement = outside_namespace - -# IDE0066, PreferSwitchExpression -csharp_style_prefer_switch_expression = true - -# IDE0070 -No editorconfig based code style option - -# IDE0071, PreferSimplifiedInterpolation -dotnet_style_prefer_simplified_interpolation = true - -# IDE0072 -No editorconfig based code style option - -# IDE0073, FileHeaderTemplate -file_header_template = unset - -# IDE0074, PreferCompoundAssignment -dotnet_style_prefer_compound_assignment = true - -# IDE0075, PreferSimplifiedBooleanExpressions -dotnet_style_prefer_simplified_boolean_expressions = true - -# IDE0076 -No editorconfig based code style option - -# IDE0077 -No editorconfig based code style option - -# IDE0078, PreferPatternMatching -csharp_style_prefer_pattern_matching = true - -# IDE0079 -No editorconfig based code style option - -# IDE0080 -No editorconfig based code style option - -# IDE0082 -No editorconfig based code style option - -# IDE0083, PreferNotPattern -csharp_style_prefer_not_pattern = true - -# IDE0090, ImplicitObjectCreationWhenTypeIsApparent -csharp_style_implicit_object_creation_when_type_is_apparent = true - -# IDE0100 -No editorconfig based code style option - -# IDE0110 -No editorconfig based code style option - -# IDE0120 -No editorconfig based code style option - -# IDE0130, PreferNamespaceAndFolderMatchStructure -dotnet_style_namespace_match_folder = true - -# IDE0150, PreferNullCheckOverTypeCheck -csharp_style_prefer_null_check_over_type_check = true - -# IDE0160, NamespaceDeclarations -csharp_style_namespace_declarations = block_scoped - -# IDE0161, NamespaceDeclarations -csharp_style_namespace_declarations = block_scoped - -# IDE0170, PreferExtendedPropertyPattern -csharp_style_prefer_extended_property_pattern = true - -# IDE0180, PreferTupleSwap -csharp_style_prefer_tuple_swap = true - -# IDE0200, PreferMethodGroupConversion -csharp_style_prefer_method_group_conversion = true - -# IDE0210, PreferTopLevelStatements -csharp_style_prefer_top_level_statements = true - -# IDE0211, PreferTopLevelStatements -csharp_style_prefer_top_level_statements = true - -# IDE0220, ForEachExplicitCastInSource -dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed - -# IDE0230, PreferUtf8StringLiterals -csharp_style_prefer_utf8_string_literals = true - -# IDE0240 -No editorconfig based code style option - -# IDE0241 -No editorconfig based code style option - -# IDE0250, PreferReadOnlyStruct -csharp_style_prefer_readonly_struct = true - -# IDE0260, PreferPatternMatchingOverAsWithNullCheck -csharp_style_pattern_matching_over_as_with_null_check = true - -# IDE0270, PreferCoalesceExpression -dotnet_style_coalesce_expression = true - -# IDE0280 -No editorconfig based code style option - -# IDE1005, PreferConditionalDelegateCall -csharp_style_conditional_delegate_call = true - -# IDE1006 -No editorconfig based code style option - -# IDE1007 -No editorconfig based code style option - -# IDE2000, AllowMultipleBlankLines -dotnet_style_allow_multiple_blank_lines_experimental = true - -# IDE2001, AllowEmbeddedStatementsOnSameLine -csharp_style_allow_embedded_statements_on_same_line_experimental = true - -# IDE2002, AllowBlankLinesBetweenConsecutiveBraces -csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true - -# IDE2003, AllowStatementImmediatelyAfterBlock -dotnet_style_allow_statement_immediately_after_block_experimental = true - -# IDE2004, AllowBlankLineAfterColonInConstructorInitializer -csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true - -# IDE2005, AllowBlankLineAfterTokenInConditionalExpression -csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true - -# IDE2006, AllowBlankLineAfterTokenInArrowExpressionClause -csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true - -# RE0001 -No editorconfig based code style option - -# JSON001 -No editorconfig based code style option - -# JSON002 -No editorconfig based code style option -"; + var expected = new[] + { + ("IDE0001", null, null), + ("IDE0002", null, null), + ("IDE0003", "dotnet_style_qualification_for_event", "false"), + ("IDE0003", "dotnet_style_qualification_for_field", "false"), + ("IDE0003", "dotnet_style_qualification_for_method", "false"), + ("IDE0003", "dotnet_style_qualification_for_property", "false"), + ("IDE0004", null, null), + ("IDE0005", null, null), + ("IDE0007", "csharp_style_var_elsewhere", "false"), + ("IDE0007", "csharp_style_var_for_built_in_types", "false"), + ("IDE0007", "csharp_style_var_when_type_is_apparent", "false"), + ("IDE0008", "csharp_style_var_elsewhere", "false"), + ("IDE0008", "csharp_style_var_for_built_in_types", "false"), + ("IDE0008", "csharp_style_var_when_type_is_apparent", "false"), + ("IDE0009", "dotnet_style_qualification_for_event", "false"), + ("IDE0009", "dotnet_style_qualification_for_field", "false"), + ("IDE0009", "dotnet_style_qualification_for_method", "false"), + ("IDE0009", "dotnet_style_qualification_for_property", "false"), + ("IDE0010", null, null), + ("IDE0011", "csharp_prefer_braces", "true"), + ("IDE0016", "csharp_style_throw_expression", "true"), + ("IDE0017", "dotnet_style_object_initializer", "true"), + ("IDE0018", "csharp_style_inlined_variable_declaration", "true"), + ("IDE0019", "csharp_style_pattern_matching_over_as_with_null_check", "true"), + ("IDE0020", "csharp_style_pattern_matching_over_is_with_cast_check", "true"), + ("IDE0021", "csharp_style_expression_bodied_constructors", "false"), + ("IDE0022", "csharp_style_expression_bodied_methods", "false"), + ("IDE0023", "csharp_style_expression_bodied_operators", "false"), + ("IDE0024", "csharp_style_expression_bodied_operators", "false"), + ("IDE0025", "csharp_style_expression_bodied_properties", "true"), + ("IDE0026", "csharp_style_expression_bodied_indexers", "true"), + ("IDE0027", "csharp_style_expression_bodied_accessors", "true"), + ("IDE0028", "dotnet_style_collection_initializer", "true"), + ("IDE0029", "dotnet_style_coalesce_expression", "true"), + ("IDE0030", "dotnet_style_coalesce_expression", "true"), + ("IDE0031", "dotnet_style_null_propagation", "true"), + ("IDE0032", "dotnet_style_prefer_auto_properties", "true"), + ("IDE0033", "dotnet_style_explicit_tuple_names", "true"), + ("IDE0034", "csharp_prefer_simple_default_expression", "true"), + ("IDE0035", null, null), + ("IDE0036", "csharp_preferred_modifier_order", "public,private,protected,internal,file,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async"), + ("IDE0037", "dotnet_style_prefer_inferred_tuple_names", "true"), + ("IDE0037", "dotnet_style_prefer_inferred_anonymous_type_member_names", "true"), + ("IDE0038", "csharp_style_pattern_matching_over_is_with_cast_check", "true"), + ("IDE0039", "csharp_style_prefer_local_over_anonymous_function", "true"), + ("IDE0040", "dotnet_style_require_accessibility_modifiers", "for_non_interface_members"), + ("IDE0041", "dotnet_style_prefer_is_null_check_over_reference_equality_method", "true"), + ("IDE0042", "csharp_style_deconstructed_variable_declaration", "true"), + ("IDE0043", null, null), + ("IDE0044", "dotnet_style_readonly_field", "true"), + ("IDE0045", "dotnet_style_prefer_conditional_expression_over_assignment", "true"), + ("IDE0046", "dotnet_style_prefer_conditional_expression_over_return", "true"), + ("IDE0047", "dotnet_style_parentheses_in_arithmetic_binary_operators", "always_for_clarity"), + ("IDE0047", "dotnet_style_parentheses_in_other_binary_operators", "always_for_clarity"), + ("IDE0047", "dotnet_style_parentheses_in_other_operators", "never_if_unnecessary"), + ("IDE0047", "dotnet_style_parentheses_in_relational_binary_operators", "always_for_clarity"), + ("IDE0048", "dotnet_style_parentheses_in_arithmetic_binary_operators", "always_for_clarity"), + ("IDE0048", "dotnet_style_parentheses_in_other_binary_operators", "always_for_clarity"), + ("IDE0048", "dotnet_style_parentheses_in_other_operators", "never_if_unnecessary"), + ("IDE0048", "dotnet_style_parentheses_in_relational_binary_operators", "always_for_clarity"), + ("IDE0049", "dotnet_style_predefined_type_for_locals_parameters_members", "true"), + ("IDE0049", "dotnet_style_predefined_type_for_member_access", "true"), + ("IDE0051", null, null), + ("IDE0052", null, null), + ("IDE0053", "csharp_style_expression_bodied_lambdas", "true"), + ("IDE0054", "dotnet_style_prefer_compound_assignment", "true"), + ("IDE0055", null, null), + ("IDE0056", "csharp_style_prefer_index_operator", "true"), + ("IDE0057", "csharp_style_prefer_range_operator", "true"), + ("IDE0058", "csharp_style_unused_value_expression_statement_preference", "discard_variable"), + ("IDE0059", "csharp_style_unused_value_assignment_preference", "discard_variable"), + ("IDE0060", "dotnet_code_quality_unused_parameters", "all"), + ("IDE0061", "csharp_style_expression_bodied_local_functions", "false"), + ("IDE0062", "csharp_prefer_static_local_function", "true"), + ("IDE0063", "csharp_prefer_simple_using_statement", "true"), + ("IDE0064", null, null), + ("IDE0065", "csharp_using_directive_placement", "outside_namespace"), + ("IDE0066", "csharp_style_prefer_switch_expression", "true"), + ("IDE0070", null, null), + ("IDE0071", "dotnet_style_prefer_simplified_interpolation", "true"), + ("IDE0072", null, null), + ("IDE0073", "file_header_template", "unset"), + ("IDE0074", "dotnet_style_prefer_compound_assignment", "true"), + ("IDE0075", "dotnet_style_prefer_simplified_boolean_expressions", "true"), + ("IDE0076", null, null), + ("IDE0077", null, null), + ("IDE0078", "csharp_style_prefer_pattern_matching", "true"), + ("IDE0079", null, null), + ("IDE0080", null, null), + ("IDE0082", null, null), + ("IDE0083", "csharp_style_prefer_not_pattern", "true"), + ("IDE0090", "csharp_style_implicit_object_creation_when_type_is_apparent", "true"), + ("IDE0100", null, null), + ("IDE0110", null, null), + ("IDE0120", 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"), + ("IDE0161", "csharp_style_namespace_declarations", "block_scoped"), + ("IDE0170", "csharp_style_prefer_extended_property_pattern", "true"), + ("IDE0180", "csharp_style_prefer_tuple_swap", "true"), + ("IDE0200", "csharp_style_prefer_method_group_conversion", "true"), + ("IDE0210", "csharp_style_prefer_top_level_statements", "true"), + ("IDE0211", "csharp_style_prefer_top_level_statements", "true"), + ("IDE0220", "dotnet_style_prefer_foreach_explicit_cast_in_source", "when_strongly_typed"), + ("IDE0230", "csharp_style_prefer_utf8_string_literals", "true"), + ("IDE0240", null, null), + ("IDE0241", null, null), + ("IDE0250", "csharp_style_prefer_readonly_struct", "true"), + ("IDE0260", "csharp_style_pattern_matching_over_as_with_null_check", "true"), + ("IDE0270", "dotnet_style_coalesce_expression", "true"), + ("IDE0280", null, null), + ("IDE1005", "csharp_style_conditional_delegate_call", "true"), + ("IDE1006", null, null), + ("IDE1007", null, null), + ("IDE2000", "dotnet_style_allow_multiple_blank_lines_experimental", "true"), + ("IDE2001", "csharp_style_allow_embedded_statements_on_same_line_experimental", "true"), + ("IDE2002", "csharp_style_allow_blank_lines_between_consecutive_braces_experimental", "true"), + ("IDE2003", "dotnet_style_allow_statement_immediately_after_block_experimental", "true"), + ("IDE2004", "csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental", "true"), + ("IDE2005", "csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental", "true"), + ("IDE2006", "csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental", "true"), + ("RE0001", null, null), + ("JSON001", null, null), + ("JSON002", null, null), + }; VerifyConfigureCodeStyleOptionsCore(expected, LanguageNames.CSharp); } @@ -1141,208 +878,76 @@ No editorconfig based code style option [Fact] public void VisualBasic_VerifyIDECodeStyleOptionsAreConfigurable() { - var expected = @" -# IDE0001 -No editorconfig based code style option - -# IDE0002 -No editorconfig based code style option - -# IDE0003, QualifyEventAccess -dotnet_style_qualification_for_event = false - -# IDE0003, QualifyFieldAccess -dotnet_style_qualification_for_field = false - -# IDE0003, QualifyMethodAccess -dotnet_style_qualification_for_method = false - -# IDE0003, QualifyPropertyAccess -dotnet_style_qualification_for_property = false - -# IDE0004 -No editorconfig based code style option - -# IDE0005 -No editorconfig based code style option - -# IDE0009, QualifyEventAccess -dotnet_style_qualification_for_event = false - -# IDE0009, QualifyFieldAccess -dotnet_style_qualification_for_field = false - -# IDE0009, QualifyMethodAccess -dotnet_style_qualification_for_method = false - -# IDE0009, QualifyPropertyAccess -dotnet_style_qualification_for_property = false - -# IDE0010 -No editorconfig based code style option - -# IDE0017, PreferObjectInitializer -dotnet_style_object_initializer = true - -# IDE0028, PreferCollectionInitializer -dotnet_style_collection_initializer = true - -# IDE0029, PreferCoalesceExpression -dotnet_style_coalesce_expression = true - -# IDE0030, PreferCoalesceExpression -dotnet_style_coalesce_expression = true - -# IDE0031, PreferNullPropagation -dotnet_style_null_propagation = true - -# IDE0032, PreferAutoProperties -dotnet_style_prefer_auto_properties = true - -# IDE0033, PreferExplicitTupleNames -dotnet_style_explicit_tuple_names = true - -# IDE0036, PreferredModifierOrder -visual_basic_preferred_modifier_order = partial,default,private,protected,public,friend,notoverridable,overridable,mustoverride,overloads,overrides,mustinherit,notinheritable,static,shared,shadows,readonly,writeonly,dim,const,withevents,widening,narrowing,custom,async,iterator - -# IDE0037, PreferInferredTupleNames -dotnet_style_prefer_inferred_tuple_names = true - -# IDE0037, PreferInferredAnonymousTypeMemberNames -dotnet_style_prefer_inferred_anonymous_type_member_names = true - -# IDE0040, RequireAccessibilityModifiers -dotnet_style_require_accessibility_modifiers = for_non_interface_members - -# IDE0041, PreferIsNullCheckOverReferenceEqualityMethod -dotnet_style_prefer_is_null_check_over_reference_equality_method = true - -# IDE0043 -No editorconfig based code style option - -# IDE0044, PreferReadonly -dotnet_style_readonly_field = true - -# IDE0045, PreferConditionalExpressionOverAssignment -dotnet_style_prefer_conditional_expression_over_assignment = true - -# IDE0046, PreferConditionalExpressionOverReturn -dotnet_style_prefer_conditional_expression_over_return = true - -# IDE0047, ArithmeticBinaryParentheses -dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity - -# IDE0047, OtherBinaryParentheses -dotnet_style_parentheses_in_other_binary_operators = always_for_clarity - -# IDE0047, OtherParentheses -dotnet_style_parentheses_in_other_operators = never_if_unnecessary - -# IDE0047, RelationalBinaryParentheses -dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity - -# IDE0048, ArithmeticBinaryParentheses -dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity - -# IDE0048, OtherBinaryParentheses -dotnet_style_parentheses_in_other_binary_operators = always_for_clarity - -# IDE0048, OtherParentheses -dotnet_style_parentheses_in_other_operators = never_if_unnecessary - -# IDE0048, RelationalBinaryParentheses -dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity - -# IDE0049, PreferIntrinsicPredefinedTypeKeywordInDeclaration -dotnet_style_predefined_type_for_locals_parameters_members = true - -# IDE0049, PreferIntrinsicPredefinedTypeKeywordInMemberAccess -dotnet_style_predefined_type_for_member_access = true - -# IDE0051 -No editorconfig based code style option - -# IDE0052 -No editorconfig based code style option - -# IDE0054, PreferCompoundAssignment -dotnet_style_prefer_compound_assignment = true - -# IDE0055 -No editorconfig based code style option - -# IDE0058, UnusedValueExpressionStatement -visual_basic_style_unused_value_expression_statement_preference = unused_local_variable - -# IDE0059, UnusedValueAssignment -visual_basic_style_unused_value_assignment_preference = unused_local_variable - -# IDE0060, UnusedParameters -dotnet_code_quality_unused_parameters = all - -# IDE0070 -No editorconfig based code style option - -# IDE0071, PreferSimplifiedInterpolation -dotnet_style_prefer_simplified_interpolation = true - -# IDE0073, FileHeaderTemplate -file_header_template = unset - -# IDE0075, PreferSimplifiedBooleanExpressions -dotnet_style_prefer_simplified_boolean_expressions = true - -# IDE0076 -No editorconfig based code style option - -# IDE0077 -No editorconfig based code style option - -# IDE0079 -No editorconfig based code style option - -# IDE0081 -No editorconfig based code style option - -# IDE0082 -No editorconfig based code style option - -# IDE0084, PreferIsNotExpression -visual_basic_style_prefer_isnot_expression = true - -# IDE0100 -No editorconfig based code style option - -# IDE1006 -No editorconfig based code style option - -# IDE1007 -No editorconfig based code style option - -# IDE0120 -No editorconfig based code style option - -# IDE0140, PreferSimplifiedObjectCreation -visual_basic_style_prefer_simplified_object_creation = true - -# IDE0270, PreferCoalesceExpression -dotnet_style_coalesce_expression = true - -# IDE2000, AllowMultipleBlankLines -dotnet_style_allow_multiple_blank_lines_experimental = true - -# IDE2003, AllowStatementImmediatelyAfterBlock -dotnet_style_allow_statement_immediately_after_block_experimental = true - -# RE0001 -No editorconfig based code style option - -# JSON001 -No editorconfig based code style option - -# JSON002 -No editorconfig based code style option -"; + var expected = new[] + { + ("IDE0001", null, null), + ("IDE0002", null, null), + ("IDE0003", "dotnet_style_qualification_for_event", "false"), + ("IDE0003", "dotnet_style_qualification_for_field", "false"), + ("IDE0003", "dotnet_style_qualification_for_method", "false"), + ("IDE0003", "dotnet_style_qualification_for_property", "false"), + ("IDE0004", null, null), + ("IDE0005", null, null), + ("IDE0009", "dotnet_style_qualification_for_event", "false"), + ("IDE0009", "dotnet_style_qualification_for_field", "false"), + ("IDE0009", "dotnet_style_qualification_for_method", "false"), + ("IDE0009", "dotnet_style_qualification_for_property", "false"), + ("IDE0010", null, null), + ("IDE0017", "dotnet_style_object_initializer", "true"), + ("IDE0028", "dotnet_style_collection_initializer", "true"), + ("IDE0029", "dotnet_style_coalesce_expression", "true"), + ("IDE0030", "dotnet_style_coalesce_expression", "true"), + ("IDE0031", "dotnet_style_null_propagation", "true"), + ("IDE0032", "dotnet_style_prefer_auto_properties", "true"), + ("IDE0033", "dotnet_style_explicit_tuple_names", "true"), + ("IDE0036", "visual_basic_preferred_modifier_order", "partial,default,private,protected,public,friend,notoverridable,overridable,mustoverride,overloads,overrides,mustinherit,notinheritable,static,shared,shadows,readonly,writeonly,dim,const,withevents,widening,narrowing,custom,async,iterator"), + ("IDE0037", "dotnet_style_prefer_inferred_anonymous_type_member_names", "true"), + ("IDE0037", "dotnet_style_prefer_inferred_tuple_names", "true"), + ("IDE0040", "dotnet_style_require_accessibility_modifiers", "for_non_interface_members"), + ("IDE0041", "dotnet_style_prefer_is_null_check_over_reference_equality_method", "true"), + ("IDE0043", null, null), + ("IDE0044", "dotnet_style_readonly_field", "true"), + ("IDE0045", "dotnet_style_prefer_conditional_expression_over_assignment", "true"), + ("IDE0046", "dotnet_style_prefer_conditional_expression_over_return", "true"), + ("IDE0047", "dotnet_style_parentheses_in_arithmetic_binary_operators", "always_for_clarity"), + ("IDE0047", "dotnet_style_parentheses_in_other_binary_operators", "always_for_clarity"), + ("IDE0047", "dotnet_style_parentheses_in_other_operators", "never_if_unnecessary"), + ("IDE0047", "dotnet_style_parentheses_in_relational_binary_operators", "always_for_clarity"), + ("IDE0048", "dotnet_style_parentheses_in_arithmetic_binary_operators", "always_for_clarity"), + ("IDE0048", "dotnet_style_parentheses_in_other_binary_operators", "always_for_clarity"), + ("IDE0048", "dotnet_style_parentheses_in_other_operators", "never_if_unnecessary"), + ("IDE0048", "dotnet_style_parentheses_in_relational_binary_operators", "always_for_clarity"), + ("IDE0049", "dotnet_style_predefined_type_for_locals_parameters_members", "true"), + ("IDE0049", "dotnet_style_predefined_type_for_member_access", "true"), + ("IDE0051", null, null), + ("IDE0052", null, null), + ("IDE0054", "dotnet_style_prefer_compound_assignment", "true"), + ("IDE0055", null, null), + ("IDE0058", "visual_basic_style_unused_value_expression_statement_preference", "unused_local_variable"), + ("IDE0059", "visual_basic_style_unused_value_assignment_preference", "unused_local_variable"), + ("IDE0060", "dotnet_code_quality_unused_parameters", "all"), + ("IDE0070", null, null), + ("IDE0071", "dotnet_style_prefer_simplified_interpolation", "true"), + ("IDE0073", "file_header_template", "unset"), + ("IDE0075", "dotnet_style_prefer_simplified_boolean_expressions", "true"), + ("IDE0076", null, null), + ("IDE0077", null, null), + ("IDE0079", null, null), + ("IDE0081", null, null), + ("IDE0082", null, null), + ("IDE0084", "visual_basic_style_prefer_isnot_expression", "true"), + ("IDE0100", null, null), + ("IDE0120", null, null), + ("IDE0140", "visual_basic_style_prefer_simplified_object_creation", "true"), + ("IDE0270", "dotnet_style_coalesce_expression", "true"), + ("IDE1006", null, null), + ("IDE1007", null, null), + ("IDE2000", "dotnet_style_allow_multiple_blank_lines_experimental", "true"), + ("IDE2003", "dotnet_style_allow_statement_immediately_after_block_experimental", "true"), + ("JSON001", null, null), + ("JSON002", null, null), + ("RE0001", null, null), + }; VerifyConfigureCodeStyleOptionsCore(expected, LanguageNames.VisualBasic); } diff --git a/src/EditorFeatures/Test/EditAndContinue/TraceLogTests.cs b/src/EditorFeatures/Test/EditAndContinue/TraceLogTests.cs index cfca7cd52e89c..9c3d0766a3a3c 100644 --- a/src/EditorFeatures/Test/EditAndContinue/TraceLogTests.cs +++ b/src/EditorFeatures/Test/EditAndContinue/TraceLogTests.cs @@ -14,7 +14,7 @@ public class TraceLogTests [Fact] public void Write() { - var log = new TraceLog(5, "log", logDirectory: null); + var log = new TraceLog(5, "log", "File.log", logDirectory: null); var projectId = ProjectId.CreateFromSerialized(Guid.Parse("5E40F37C-5AB3-495E-A3F2-4A244D177674"), debugName: "MyProject"); var diagnostic = Diagnostic.Create(EditAndContinueDiagnosticDescriptors.GetDescriptor(EditAndContinueErrorCode.ErrorReadingFile), Location.None, "file", "error"); diff --git a/src/EditorFeatures/Test/EditorConfigSettings/Data/CodeStyleSettingsTest.cs b/src/EditorFeatures/Test/EditorConfigSettings/Data/CodeStyleSettingsTest.cs index e71541af7164a..eef70984a5ca3 100644 --- a/src/EditorFeatures/Test/EditorConfigSettings/Data/CodeStyleSettingsTest.cs +++ b/src/EditorFeatures/Test/EditorConfigSettings/Data/CodeStyleSettingsTest.cs @@ -2,7 +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. -extern alias WORKSPACES; using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; @@ -10,24 +9,31 @@ using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; -using Microsoft.CodeAnalysis.UnitTests; -using WORKSPACES::Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Options; using Xunit; namespace Microsoft.CodeAnalysis.Editor.UnitTests.EditorConfigSettings.Data { + [UseExportProvider] public class CodeStyleSettingsTest { + private static IGlobalOptionService GetGlobalOptions(Workspace workspace) + => workspace.Services.SolutionServices.ExportProvider.GetExportedValue(); + [Theory] [InlineData(true)] [InlineData(false)] public static void CodeStyleSettingBoolFactory(bool defaultValue) { + using var workspace = new AdhocWorkspace(); + var globalOptions = GetGlobalOptions(workspace); + var option = CreateBoolOption(defaultValue); var options = new TieredAnalyzerConfigOptions( new TestAnalyzerConfigOptions(), - new TestAnalyzerConfigOptions(new[] { ("csharp_test_option", "default") }), + globalOptions, LanguageNames.CSharp, ".editorconfig"); @@ -44,11 +50,14 @@ public static void CodeStyleSettingBoolFactory(bool defaultValue) [InlineData(DayOfWeek.Friday)] public static void CodeStyleSettingEnumFactory(DayOfWeek defaultValue) { + using var workspace = new AdhocWorkspace(); + var globalOptions = GetGlobalOptions(workspace); + var option = CreateEnumOption(defaultValue); var options = new TieredAnalyzerConfigOptions( new TestAnalyzerConfigOptions(), - new TestAnalyzerConfigOptions(new[] { ("csharp_test_option", "default") }), + globalOptions, LanguageNames.CSharp, ".editorconfig"); @@ -72,10 +81,10 @@ private static Option2> CreateBoolOption(bool defaultValu var defaultCodeStyle = (CodeStyleOption2)((ICodeStyleOption)CodeStyleOption2.Default).WithValue(defaultValue); return new Option2>( - feature: "TestFeature", - name: "TestOption", + name: "dotnet_test_option", defaultValue: defaultCodeStyle, - new EditorConfigStorageLocation>("csharp_test_option", _ => defaultCodeStyle, _ => "default")); + serializer: new EditorConfigValueSerializer>(_ => defaultCodeStyle, _ => "default"), + isEditorConfigOption: true); } private static Option2> CreateEnumOption(T defaultValue) @@ -83,10 +92,10 @@ private static Option2> CreateEnumOption(T defaultValue) { var defaultCodeStyle = (CodeStyleOption2)((ICodeStyleOption)CodeStyleOption2.Default).WithValue(defaultValue); return new Option2>( - feature: "TestFeature", - name: "TestOption", + name: "dotnet_test_option", defaultValue: defaultCodeStyle, - new EditorConfigStorageLocation>("csharp_test_option", _ => defaultCodeStyle, _ => "default")); + serializer: new EditorConfigValueSerializer>(_ => defaultCodeStyle, _ => "default"), + isEditorConfigOption: true); } private class TestAnalyzerConfigOptions : AnalyzerConfigOptions @@ -97,14 +106,5 @@ public TestAnalyzerConfigOptions((string, string)[]? options = null) public override bool TryGetValue(string key, [NotNullWhen(true)] out string? value) => _dictionary.TryGetValue(key, out value); } - - private class TestOptionSet : OptionSet - { - private readonly object? _value; - public TestOptionSet(CodeStyleOption2 value) => _value = value; - public override OptionSet WithChangedOption(OptionKey optionAndLanguage, object? value) => this; - internal override IEnumerable GetChangedOptions(OptionSet optionSet) => Array.Empty(); - private protected override object? GetOptionCore(OptionKey optionKey) => _value; - } } } diff --git a/src/EditorFeatures/Test/Options/GlobalOptionsTests.cs b/src/EditorFeatures/Test/Options/GlobalOptionsTests.cs index 76ab16db3ae76..4bf9f8496f08a 100644 --- a/src/EditorFeatures/Test/Options/GlobalOptionsTests.cs +++ b/src/EditorFeatures/Test/Options/GlobalOptionsTests.cs @@ -24,6 +24,7 @@ using Microsoft.CodeAnalysis.ExtractMethod; using Microsoft.CodeAnalysis.FindUsages; using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.ImplementType; using Microsoft.CodeAnalysis.InlineHints; @@ -43,7 +44,7 @@ public class GlobalOptionsTests [Export(typeof(IGlobalOptionService)), Shared, PartNotDiscoverable] internal class TestGlobalOptions : IGlobalOptionService { - public readonly List AccessedOptionKeys = new(); + public readonly List AccessedOptionKeys = new(); [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] @@ -51,120 +52,62 @@ public TestGlobalOptions() { } - private void OnOptionAccessed(OptionKey key) + private void OnOptionAccessed(OptionKey2 key) { AccessedOptionKeys.Add(key); } - public T GetOption(Option2 option) + bool IOptionsReader.TryGetOption(OptionKey2 optionKey, out T value) { - OnOptionAccessed(new OptionKey(option)); - return (T)GetNonEqualValue(typeof(T), option.DefaultValue); + value = GetOption(optionKey); + return true; } - public T GetOption(PerLanguageOption2 option, string? languageName) - { - OnOptionAccessed(new OptionKey(option, languageName)); - return (T)GetNonEqualValue(typeof(T), option.DefaultValue); - } - - public object? GetOption(OptionKey optionKey) - => throw new NotImplementedException(); + public T GetOption(Option2 option) + => GetOption(new OptionKey2(option)); - #region Unused + public T GetOption(PerLanguageOption2 option, string languageName) + => GetOption(new OptionKey2(option, languageName)); - public void RegisterWorkspace(Workspace workspace) + public T GetOption(OptionKey2 optionKey) { + OnOptionAccessed(optionKey); + return (T)OptionsTestHelpers.GetDifferentValue(typeof(T), optionKey.Option.DefaultValue)!; } - public void UnregisterWorkspace(Workspace workspace) - { - } + #region Unused #pragma warning disable CS0067 public event EventHandler? OptionChanged; #pragma warning restore - public ImmutableArray GetOptions(ImmutableArray optionKeys) + public ImmutableArray GetOptions(ImmutableArray optionKeys) => throw new NotImplementedException(); - public void RefreshOption(OptionKey optionKey, object? newValue) + public bool RefreshOption(OptionKey2 optionKey, object? newValue) => throw new NotImplementedException(); - public void SetGlobalOption(OptionKey optionKey, object? value) + public void SetGlobalOption(Option2 option, T value) => throw new NotImplementedException(); - public void SetGlobalOptions(ImmutableArray optionKeys, ImmutableArray values) + public void SetGlobalOption(PerLanguageOption2 option, string language, T value) => throw new NotImplementedException(); - public void SetOptions(OptionSet optionSet, IEnumerable optionKeys) + public void SetGlobalOption(OptionKey2 optionKey, object? value) => throw new NotImplementedException(); - #endregion - } - - /// - /// True if the type is a type of an option value. - /// - private static bool IsOptionValueType(Type type) - { - type = GetNonNullableType(type); - - return - type == typeof(bool) || - type == typeof(int) || - type == typeof(string) || - type.IsEnum || - type == typeof(NamingStylePreferences) || - typeof(ICodeStyleOption).IsAssignableFrom(type); - } - - private static Type GetNonNullableType(Type type) - => type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>) ? type.GetGenericArguments()[0] : type; - - /// - /// Returns another value of the same type that's not equal to the specified . - /// - private static object GetNonEqualValue(Type type, object? value) - { - Assert.True(IsOptionValueType(type)); - - switch (value) - { - case bool b: - return !b; - - case int i: - return i == 0 ? 1 : 0; - - case string s: - return "!" + s; - - case ICodeStyleOption codeStyle: - return codeStyle - .WithValue(GetNonEqualValue(codeStyle.GetType().GetGenericArguments()[0], codeStyle.Value)) - .WithNotification((codeStyle.Notification == NotificationOption2.Error) ? NotificationOption2.Warning : NotificationOption2.Error); - - case NamingStylePreferences naming: - return naming.IsEmpty ? NamingStylePreferences.Default : NamingStylePreferences.Empty; - - default: - if (value != null && type.IsEnum) - { - var zero = Enum.ToObject(type, 0); - return value.Equals(zero) ? Enum.ToObject(type, 1) : zero; - } + public bool SetGlobalOptions(ImmutableArray> options) + => throw new NotImplementedException(); - throw TestExceptionUtilities.UnexpectedValue(value); - } + #endregion } - private static void VerifyDataMembersHaveNonDefaultValues(object options, object defaultOptions, string language) + private static void VerifyDataMembersHaveNonDefaultValues(object options, object defaultOptions, string? language = null) { Assert.Equal(options.GetType(), defaultOptions.GetType()); Recurse(options.GetType(), options, defaultOptions, language); - static void Recurse(Type type, object options, object defaultOptions, string language) + static void Recurse(Type type, object options, object defaultOptions, string? language) { foreach (var property in type.GetProperties(BindingFlags.Instance | BindingFlags.Public)) { @@ -176,7 +119,7 @@ static void Recurse(Type type, object options, object defaultOptions, string lan // default value for the option -- may be different then default(T): var defaultValue = property.GetValue(defaultOptions); - if (IsOptionValueType(property.PropertyType)) + if (OptionsTestHelpers.IsOptionValueType(property.PropertyType)) { if (IsStoredInGlobalOptions(property, language)) { @@ -185,7 +128,7 @@ static void Recurse(Type type, object options, object defaultOptions, string lan } else { - var propertyType = GetNonNullableType(property.PropertyType); + var propertyType = OptionsTestHelpers.GetNonNullableType(property.PropertyType); if (propertyType != property.PropertyType) { @@ -215,7 +158,7 @@ private static TestWorkspace CreateWorkspace(out TestGlobalOptions globalOptions /// /// Properties for options not stored in global options. /// - private static bool IsStoredInGlobalOptions(PropertyInfo property, string language) + private static bool IsStoredInGlobalOptions(PropertyInfo property, string? language) => !(property.DeclaringType == typeof(AddImportPlacementOptions) && property.Name == nameof(AddImportPlacementOptions.AllowInHiddenRegions) || property.DeclaringType == typeof(AddImportPlacementOptions) && property.Name == nameof(AddImportPlacementOptions.UsingDirectivePlacement) && language == LanguageNames.VisualBasic || property.DeclaringType == typeof(DocumentFormattingOptions) && property.Name == nameof(DocumentFormattingOptions.FileHeaderTemplate) || @@ -225,8 +168,9 @@ private static bool IsStoredInGlobalOptions(PropertyInfo property, string langua /// /// Our mock implementation returns a non-default value for each option it reads. - /// Option objects initialized from this service thus should have all their data properties initialized to non-default values. - /// We then enumerate these properties via reflection and compare each property value with the default instance of the respective options type. + /// Option objects initialized from this service thus should have all their data properties initialized to + /// non-default values. We then enumerate these properties via reflection and compare each property value with the + /// default instance of the respective options type. /// [Theory] [InlineData(LanguageNames.CSharp)] @@ -249,5 +193,6 @@ public void ReadingOptionsFromGlobalOptions(string language) VerifyDataMembersHaveNonDefaultValues(globalOptions.GetMetadataAsSourceOptions(languageServices), MetadataAsSourceOptions.GetDefault(languageServices), language); VerifyDataMembersHaveNonDefaultValues(globalOptions.GetSignatureHelpOptions(language), SignatureHelpOptions.Default, language); VerifyDataMembersHaveNonDefaultValues(globalOptions.GetSymbolSearchOptions(language), SymbolSearchOptions.Default, language); + VerifyDataMembersHaveNonDefaultValues(globalOptions.GetWorkspaceConfigurationOptions(), WorkspaceConfigurationOptions.Default); } } diff --git a/src/EditorFeatures/Test/SolutionCrawler/WorkCoordinatorTests.cs b/src/EditorFeatures/Test/SolutionCrawler/WorkCoordinatorTests.cs index f5f9a52cb11a7..cf1624384a24d 100644 --- a/src/EditorFeatures/Test/SolutionCrawler/WorkCoordinatorTests.cs +++ b/src/EditorFeatures/Test/SolutionCrawler/WorkCoordinatorTests.cs @@ -481,7 +481,7 @@ public async Task Test_NeedsReanalysisOnOptionChanged() workspace.OnSolutionAdded(solutionInfo); await WaitWaiterAsync(workspace.ExportProvider); - var worker = await ExecuteOperation(workspace, w => w.TryApplyChanges(w.CurrentSolution.WithOptions(w.CurrentSolution.Options.WithChangedOption(Analyzer.TestOption, false)))); + var worker = await ExecuteOperation(workspace, w => w.GlobalOptions.SetGlobalOption(Analyzer.TestOption, false)); Assert.Equal(10, worker.SyntaxDocumentIds.Count); Assert.Equal(10, worker.DocumentIds.Count); @@ -500,7 +500,7 @@ public async Task Test_BackgroundAnalysisScopeOptionChanged_OpenFiles() Assert.Equal(BackgroundAnalysisScope.ActiveFile, workspace.GlobalOptions.GetBackgroundAnalysisScope(LanguageNames.CSharp)); var newAnalysisScope = BackgroundAnalysisScope.OpenFiles; - var worker = await ExecuteOperation(workspace, w => w.GlobalOptions.SetGlobalOption(new OptionKey(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp), newAnalysisScope)); + var worker = await ExecuteOperation(workspace, w => w.GlobalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp, newAnalysisScope)); Assert.Equal(newAnalysisScope, workspace.GlobalOptions.GetBackgroundAnalysisScope(LanguageNames.CSharp)); Assert.Equal(10, worker.SyntaxDocumentIds.Count); @@ -519,7 +519,7 @@ public async Task Test_BackgroundAnalysisScopeOptionChanged_FullSolution() Assert.Equal(BackgroundAnalysisScope.ActiveFile, workspace.GlobalOptions.GetBackgroundAnalysisScope(LanguageNames.CSharp)); var newAnalysisScope = BackgroundAnalysisScope.FullSolution; - var worker = await ExecuteOperation(workspace, w => w.GlobalOptions.SetGlobalOption(new OptionKey(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp), newAnalysisScope)); + var worker = await ExecuteOperation(workspace, w => w.GlobalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp, newAnalysisScope)); Assert.Equal(newAnalysisScope, workspace.GlobalOptions.GetBackgroundAnalysisScope(LanguageNames.CSharp)); Assert.Equal(10, worker.SyntaxDocumentIds.Count); @@ -1704,7 +1704,7 @@ public static WorkCoordinatorWorkspace CreateWithAnalysisScope(BackgroundAnalysi var workspace = new WorkCoordinatorWorkspace(workspaceKind, disablePartialSolutions, incrementalAnalyzer); var globalOptions = workspace.Services.SolutionServices.ExportProvider.GetExportedValue(); - globalOptions.SetGlobalOption(new OptionKey(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp), analysisScope); + globalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp, analysisScope); return workspace; } @@ -1788,7 +1788,7 @@ internal static class Metadata private class Analyzer : IIncrementalAnalyzer { - public static readonly Option2 TestOption = new Option2("TestOptions", "TestOption", defaultValue: true); + public static readonly Option2 TestOption = new Option2("TestOptions_TestOption", defaultValue: true); public readonly ManualResetEventSlim BlockEvent; public readonly ManualResetEventSlim RunningEvent; diff --git a/src/EditorFeatures/Test/Structure/StructureTaggerTests.cs b/src/EditorFeatures/Test/Structure/StructureTaggerTests.cs index 2f84c615c20fa..69251dce7b485 100644 --- a/src/EditorFeatures/Test/Structure/StructureTaggerTests.cs +++ b/src/EditorFeatures/Test/Structure/StructureTaggerTests.cs @@ -56,9 +56,9 @@ static void Main(string[] args) using var workspace = TestWorkspace.CreateCSharp(code, composition: EditorTestCompositions.EditorFeaturesWpf); var globalOptions = workspace.GlobalOptions; - globalOptions.SetGlobalOption(new OptionKey(BlockStructureOptionsStorage.CollapseRegionsWhenCollapsingToDefinitions, LanguageNames.CSharp), collapseRegionsWhenCollapsingToDefinitions); - globalOptions.SetGlobalOption(new OptionKey(BlockStructureOptionsStorage.ShowBlockStructureGuidesForDeclarationLevelConstructs, LanguageNames.CSharp), showBlockStructureGuidesForDeclarationLevelConstructs); - globalOptions.SetGlobalOption(new OptionKey(BlockStructureOptionsStorage.ShowBlockStructureGuidesForCodeLevelConstructs, LanguageNames.CSharp), showBlockStructureGuidesForCodeLevelConstructs); + globalOptions.SetGlobalOption(BlockStructureOptionsStorage.CollapseRegionsWhenCollapsingToDefinitions, LanguageNames.CSharp, collapseRegionsWhenCollapsingToDefinitions); + globalOptions.SetGlobalOption(BlockStructureOptionsStorage.ShowBlockStructureGuidesForDeclarationLevelConstructs, LanguageNames.CSharp, showBlockStructureGuidesForDeclarationLevelConstructs); + globalOptions.SetGlobalOption(BlockStructureOptionsStorage.ShowBlockStructureGuidesForCodeLevelConstructs, LanguageNames.CSharp, showBlockStructureGuidesForCodeLevelConstructs); var tags = await GetTagsFromWorkspaceAsync(workspace); @@ -122,9 +122,9 @@ public class Bar using var workspace = TestWorkspace.CreateCSharp(code, composition: EditorTestCompositions.EditorFeaturesWpf); var globalOptions = workspace.GlobalOptions; - globalOptions.SetGlobalOption(new OptionKey(BlockStructureOptionsStorage.CollapseRegionsWhenCollapsingToDefinitions, LanguageNames.CSharp), collapseRegionsWhenCollapsingToDefinitions); - globalOptions.SetGlobalOption(new OptionKey(BlockStructureOptionsStorage.ShowBlockStructureGuidesForDeclarationLevelConstructs, LanguageNames.CSharp), showBlockStructureGuidesForDeclarationLevelConstructs); - globalOptions.SetGlobalOption(new OptionKey(BlockStructureOptionsStorage.ShowBlockStructureGuidesForCodeLevelConstructs, LanguageNames.CSharp), showBlockStructureGuidesForCodeLevelConstructs); + globalOptions.SetGlobalOption(BlockStructureOptionsStorage.CollapseRegionsWhenCollapsingToDefinitions, LanguageNames.CSharp, collapseRegionsWhenCollapsingToDefinitions); + globalOptions.SetGlobalOption(BlockStructureOptionsStorage.ShowBlockStructureGuidesForDeclarationLevelConstructs, LanguageNames.CSharp, showBlockStructureGuidesForDeclarationLevelConstructs); + globalOptions.SetGlobalOption(BlockStructureOptionsStorage.ShowBlockStructureGuidesForCodeLevelConstructs, LanguageNames.CSharp, showBlockStructureGuidesForCodeLevelConstructs); var tags = await GetTagsFromWorkspaceAsync(workspace); @@ -167,10 +167,10 @@ public class Bar using var workspace = TestWorkspace.CreateCSharp(code, composition: EditorTestCompositions.EditorFeaturesWpf); var globalOptions = workspace.GlobalOptions; - globalOptions.SetGlobalOption(new OptionKey(BlockStructureOptionsStorage.CollapseRegionsWhenCollapsingToDefinitions, LanguageNames.CSharp), collapseRegionsWhenCollapsingToDefinitions); - globalOptions.SetGlobalOption(new OptionKey(BlockStructureOptionsStorage.ShowBlockStructureGuidesForDeclarationLevelConstructs, LanguageNames.CSharp), showBlockStructureGuidesForDeclarationLevelConstructs); - globalOptions.SetGlobalOption(new OptionKey(BlockStructureOptionsStorage.ShowBlockStructureGuidesForCodeLevelConstructs, LanguageNames.CSharp), showBlockStructureGuidesForCodeLevelConstructs); - globalOptions.SetGlobalOption(new OptionKey(BlockStructureOptionsStorage.ShowBlockStructureGuidesForCommentsAndPreprocessorRegions, LanguageNames.CSharp), showBlockStructureGuidesForCommentsAndPreprocessorRegions); + globalOptions.SetGlobalOption(BlockStructureOptionsStorage.CollapseRegionsWhenCollapsingToDefinitions, LanguageNames.CSharp, collapseRegionsWhenCollapsingToDefinitions); + globalOptions.SetGlobalOption(BlockStructureOptionsStorage.ShowBlockStructureGuidesForDeclarationLevelConstructs, LanguageNames.CSharp, showBlockStructureGuidesForDeclarationLevelConstructs); + globalOptions.SetGlobalOption(BlockStructureOptionsStorage.ShowBlockStructureGuidesForCodeLevelConstructs, LanguageNames.CSharp, showBlockStructureGuidesForCodeLevelConstructs); + globalOptions.SetGlobalOption(BlockStructureOptionsStorage.ShowBlockStructureGuidesForCommentsAndPreprocessorRegions, LanguageNames.CSharp, showBlockStructureGuidesForCommentsAndPreprocessorRegions); var tags = await GetTagsFromWorkspaceAsync(workspace); @@ -212,9 +212,9 @@ public class Bar using var workspace = TestWorkspace.CreateCSharp(code, composition: EditorTestCompositions.EditorFeaturesWpf); var globalOptions = workspace.GlobalOptions; - globalOptions.SetGlobalOption(new OptionKey(BlockStructureOptionsStorage.CollapseRegionsWhenCollapsingToDefinitions, LanguageNames.CSharp), collapseRegionsWhenCollapsingToDefinitions); - globalOptions.SetGlobalOption(new OptionKey(BlockStructureOptionsStorage.ShowBlockStructureGuidesForDeclarationLevelConstructs, LanguageNames.CSharp), showBlockStructureGuidesForDeclarationLevelConstructs); - globalOptions.SetGlobalOption(new OptionKey(BlockStructureOptionsStorage.ShowBlockStructureGuidesForCodeLevelConstructs, LanguageNames.CSharp), showBlockStructureGuidesForCodeLevelConstructs); + globalOptions.SetGlobalOption(BlockStructureOptionsStorage.CollapseRegionsWhenCollapsingToDefinitions, LanguageNames.CSharp, collapseRegionsWhenCollapsingToDefinitions); + globalOptions.SetGlobalOption(BlockStructureOptionsStorage.ShowBlockStructureGuidesForDeclarationLevelConstructs, LanguageNames.CSharp, showBlockStructureGuidesForDeclarationLevelConstructs); + globalOptions.SetGlobalOption(BlockStructureOptionsStorage.ShowBlockStructureGuidesForCodeLevelConstructs, LanguageNames.CSharp, showBlockStructureGuidesForCodeLevelConstructs); var tags = await GetTagsFromWorkspaceAsync(workspace); @@ -264,9 +264,9 @@ End Module using var workspace = TestWorkspace.CreateVisualBasic(code, composition: EditorTestCompositions.EditorFeaturesWpf); var globalOptions = workspace.GlobalOptions; - globalOptions.SetGlobalOption(new OptionKey(BlockStructureOptionsStorage.CollapseRegionsWhenCollapsingToDefinitions, LanguageNames.VisualBasic), collapseRegionsWhenCollapsingToDefinitions); - globalOptions.SetGlobalOption(new OptionKey(BlockStructureOptionsStorage.ShowBlockStructureGuidesForDeclarationLevelConstructs, LanguageNames.VisualBasic), showBlockStructureGuidesForDeclarationLevelConstructs); - globalOptions.SetGlobalOption(new OptionKey(BlockStructureOptionsStorage.ShowBlockStructureGuidesForCodeLevelConstructs, LanguageNames.VisualBasic), showBlockStructureGuidesForCodeLevelConstructs); + globalOptions.SetGlobalOption(BlockStructureOptionsStorage.CollapseRegionsWhenCollapsingToDefinitions, LanguageNames.VisualBasic, collapseRegionsWhenCollapsingToDefinitions); + globalOptions.SetGlobalOption(BlockStructureOptionsStorage.ShowBlockStructureGuidesForDeclarationLevelConstructs, LanguageNames.VisualBasic, showBlockStructureGuidesForDeclarationLevelConstructs); + globalOptions.SetGlobalOption(BlockStructureOptionsStorage.ShowBlockStructureGuidesForCodeLevelConstructs, LanguageNames.VisualBasic, showBlockStructureGuidesForCodeLevelConstructs); var tags = await GetTagsFromWorkspaceAsync(workspace); diff --git a/src/EditorFeatures/Test2/Classification/ClassificationTests.vb b/src/EditorFeatures/Test2/Classification/ClassificationTests.vb index ed4ab55828006..7fe597794057a 100644 --- a/src/EditorFeatures/Test2/Classification/ClassificationTests.vb +++ b/src/EditorFeatures/Test2/Classification/ClassificationTests.vb @@ -22,8 +22,58 @@ Imports Microsoft.VisualStudio.Text.Tagging Imports Roslyn.Utilities Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Classification - <[UseExportProvider]> + Public Class ClassificationTests + + Public Async Function TestClassificationAndHighlight1() As Task + Using workspace = TestWorkspace.Create( + + + + using System.Text.RegularExpressions; + + class C + { + [| Regex |]re = new Regex("()"); + } + + + ) + + Dim document = workspace.CurrentSolution.Projects.Single().Documents.Single() + Dim text = Await document.GetTextAsync() + Dim referenceSpan = workspace.Documents.Single().SelectedSpans.Single() + + Dim spansAndHighlightSpan = Await ClassifiedSpansAndHighlightSpanFactory.ClassifyAsync( + New DocumentSpan(document, referenceSpan), + ClassificationOptions.Default, CancellationToken.None) + + ' This is the classification of the line, starting at the beginning of the highlight, and going to the end of that line. + Assert.Equal( +"(text, '', [154..155)) +(class name, 'Regex', [155..160)) +(text, '', [160..161)) +(field name, 're', [161..163)) +(text, '', [163..164)) +(operator, '=', [164..165)) +(text, '', [165..166)) +(keyword, 'new', [166..169)) +(text, '', [169..170)) +(class name, 'Regex', [170..175)) +(punctuation, '(', [175..176)) +(string, '""', [176..177)) +(regex - grouping, '(', [177..178)) +(regex - grouping, ')', [178..179)) +(string, '""', [179..180)) +(punctuation, ')', [180..181)) +(punctuation, ';', [181..182))", String.Join(vbCrLf, spansAndHighlightSpan.ClassifiedSpans.Select(Function(s) ToTestString(text, s)))) + + ' The portion of the classified spans to highlight goes from the start of the classified spans to the + ' length of the original reference span. + Assert.Equal(New TextSpan(0, referenceSpan.Length), spansAndHighlightSpan.HighlightSpan) + End Using + End Function + Public Async Function TestEmbeddedClassifications1() As Task Using workspace = TestWorkspace.Create( diff --git a/src/EditorFeatures/Test2/Diagnostics/DiagnosticProviderTests.vb b/src/EditorFeatures/Test2/Diagnostics/DiagnosticProviderTests.vb index 4b7ae50ccfc70..8cdf29232fad2 100644 --- a/src/EditorFeatures/Test2/Diagnostics/DiagnosticProviderTests.vb +++ b/src/EditorFeatures/Test2/Diagnostics/DiagnosticProviderTests.vb @@ -260,7 +260,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests Using workspace = TestWorkspace.CreateWorkspace(test, composition:=s_composition) ' Ensure that diagnostic service computes diagnostics for all open files, not just the active file (default mode) For Each language In workspace.Projects.Select(Function(p) p.Language).Distinct() - workspace.GlobalOptions.SetGlobalOption(New OptionKey(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, language), BackgroundAnalysisScope.OpenFiles) + workspace.GlobalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, language, BackgroundAnalysisScope.OpenFiles) Next Dim registrationService = workspace.Services.GetService(Of ISolutionCrawlerRegistrationService)() diff --git a/src/EditorFeatures/Test2/Diagnostics/DiagnosticServiceTests.vb b/src/EditorFeatures/Test2/Diagnostics/DiagnosticServiceTests.vb index 9e2c799397a16..83a17202847a2 100644 --- a/src/EditorFeatures/Test2/Diagnostics/DiagnosticServiceTests.vb +++ b/src/EditorFeatures/Test2/Diagnostics/DiagnosticServiceTests.vb @@ -2149,7 +2149,7 @@ class MyClass Using workspace = TestWorkspace.CreateWorkspace(test, composition:=s_compositionWithMockDiagnosticUpdateSourceRegistrationService) - workspace.GlobalOptions.SetGlobalOption(New OptionKey(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp), BackgroundAnalysisScope.FullSolution) + workspace.GlobalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp, BackgroundAnalysisScope.FullSolution) Dim solution = workspace.CurrentSolution Dim project = solution.Projects.Single() diff --git a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.LocalSymbols.vb b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.LocalSymbols.vb index cbd9e259dbcfe..c992c85e6681f 100644 --- a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.LocalSymbols.vb +++ b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.LocalSymbols.vb @@ -618,6 +618,36 @@ class C } + + Await TestAPIAndFeature(input, kind, host) + End Function + + + + Public Async Function TestLocal_ErrorDuplicateMethodInDifferentFiles(kind As TestKind, host As TestHost) As Task + Dim input = + + + +partial class C +{ + int M() + { + var {|Definition:$$goo|} = 1; + return [|goo|]; + } +} + + +partial class C +{ + int M() + { + return goo; + } +} + + Await TestAPIAndFeature(input, kind, host) End Function diff --git a/src/EditorFeatures/Test2/InlineHints/AbstractInlineHintsTests.vb b/src/EditorFeatures/Test2/InlineHints/AbstractInlineHintsTests.vb index 4cac10d5597da..4fd7459b32625 100644 --- a/src/EditorFeatures/Test2/InlineHints/AbstractInlineHintsTests.vb +++ b/src/EditorFeatures/Test2/InlineHints/AbstractInlineHintsTests.vb @@ -77,7 +77,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.InlineHints WpfTestRunner.RequireWpfFact($"{NameOf(AbstractInlineHintsTests)}.{NameOf(Me.VerifyTypeHints)} creates asynchronous taggers") Dim globalOptions = workspace.GetService(Of IGlobalOptionService) - globalOptions.SetGlobalOption(New OptionKey(InlineHintsGlobalStateOption.DisplayAllOverride), ephemeral) + globalOptions.SetGlobalOption(InlineHintsGlobalStateOption.DisplayAllOverride, ephemeral) Dim options = New InlineTypeHintsOptions() With { diff --git a/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb b/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb index ff543c0efbd38..5400b962d4c23 100644 --- a/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb +++ b/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb @@ -112,8 +112,7 @@ namespace NS excludedTypes:=Nothing, extraExportedTypes:=Nothing, includeFormatCommandHandler:=False, workspaceKind:=Nothing) - State.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionOptionsStorage.TriggerInArgumentLists, LanguageNames.CSharp), showCompletionInArgumentLists) + State.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.TriggerInArgumentLists, LanguageNames.CSharp, showCompletionInArgumentLists) State.SendTypeChars("F") Await State.AssertCompletionItemsDoNotContainAny("FC") @@ -147,8 +146,7 @@ namespace NS excludedTypes:=Nothing, extraExportedTypes:=Nothing, includeFormatCommandHandler:=False, workspaceKind:=Nothing) - State.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionOptionsStorage.TriggerInArgumentLists, LanguageNames.CSharp), showCompletionInArgumentLists) + State.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.TriggerInArgumentLists, LanguageNames.CSharp, showCompletionInArgumentLists) State.SendTypeChars("F") Await State.AssertCompletionItemsDoNotContainAny("FC") @@ -895,8 +893,7 @@ class C , showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp, True) state.SendTypeChars("repl") state.SendTab() @@ -1146,7 +1143,7 @@ class Class1 }, showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.EnterKeyBehavior, LanguageNames.CSharp), EnterKeyRule.AfterFullyTypedWord) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.EnterKeyBehavior, LanguageNames.CSharp, EnterKeyRule.AfterFullyTypedWord) state.SendTypeChars("System.TimeSpan.FromMin") state.SendReturn() @@ -1174,8 +1171,7 @@ class Class1 }, showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionOptionsStorage.EnterKeyBehavior, LanguageNames.CSharp), EnterKeyRule.AfterFullyTypedWord) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.EnterKeyBehavior, LanguageNames.CSharp, EnterKeyRule.AfterFullyTypedWord) state.SendTypeChars("System.TimeSpan.FromMinutes") state.SendReturn() @@ -1518,8 +1514,7 @@ class Variable }]]>, showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp, True) state.SendBackspace() Await state.AssertSelectedCompletionItem(displayText:="as", isSoftSelected:=True) @@ -1547,8 +1542,7 @@ class Variable }]]>, showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp, True) state.SendBackspace() Await state.AssertSelectedCompletionItem(displayText:="as", isSoftSelected:=True) @@ -4105,8 +4099,7 @@ class$$ C }]]>, showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp, True) state.SendBackspace() Await state.AssertCompletionSession() @@ -4135,8 +4128,7 @@ class Program }]]>, showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp, True) state.SendBackspace() Await state.AssertCompletionSession() @@ -4829,8 +4821,7 @@ class Program ]]>, showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp, True) For Each c In "Offset" state.SendBackspace() @@ -4858,8 +4849,7 @@ class Program ]]>, showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp, True) For Each c In "Offset." state.SendBackspace() @@ -4984,8 +4974,7 @@ class C Dim completionService = state.Workspace.Services.GetLanguageServices(LanguageNames.CSharp).GetRequiredService(Of CompletionService)() Dim provider = completionService.GetTestAccessor().GetImportedAndBuiltInProviders(ImmutableHashSet(Of String).Empty).OfType(Of BooleanTaskControlledCompletionProvider)().Single() - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionViewOptions.BlockForCompletionItems, LanguageNames.CSharp), False) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionViewOptions.BlockForCompletionItems, LanguageNames.CSharp, False) state.SendTypeChars("Sys.") Await state.AssertNoCompletionSession() @@ -5004,8 +4993,7 @@ class C extraExportedTypes:={GetType(CompletedTaskControlledCompletionProvider)}.ToList(), showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionViewOptions.BlockForCompletionItems, LanguageNames.CSharp), False) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionViewOptions.BlockForCompletionItems, LanguageNames.CSharp, False) state.SendTypeChars("Sys") Await state.AssertSelectedCompletionItem(displayText:="System") @@ -5037,8 +5025,7 @@ class C Dim completionService = state.Workspace.Services.GetLanguageServices(LanguageNames.CSharp).GetRequiredService(Of CompletionService)() Dim provider = completionService.GetTestAccessor().GetImportedAndBuiltInProviders(ImmutableHashSet(Of String).Empty).OfType(Of BooleanTaskControlledCompletionProvider)().Single() - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionViewOptions.BlockForCompletionItems, LanguageNames.CSharp), False) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionViewOptions.BlockForCompletionItems, LanguageNames.CSharp, False) state.SendTypeChars("Sys") @@ -5115,7 +5102,7 @@ class C Dim provider = completionService.GetTestAccessor().GetImportedAndBuiltInProviders(ImmutableHashSet(Of String).Empty).OfType(Of BooleanTaskControlledCompletionProvider)().Single() Dim globalOptions = state.Workspace.GetService(Of IGlobalOptionService) - globalOptions.SetGlobalOption(New OptionKey(CompletionViewOptions.BlockForCompletionItems, LanguageNames.CSharp), False) + globalOptions.SetGlobalOption(CompletionViewOptions.BlockForCompletionItems, LanguageNames.CSharp, False) state.SendTypeChars("Sys") Dim task1 As Task = Nothing @@ -5206,7 +5193,7 @@ class C provider.Reset() ' Switch to the non-blocking mode - globalOptions.SetGlobalOption(New OptionKey(CompletionViewOptions.BlockForCompletionItems, LanguageNames.CSharp), False) + globalOptions.SetGlobalOption(CompletionViewOptions.BlockForCompletionItems, LanguageNames.CSharp, False) ' re-use of TestNoBlockOnCompletionItems1 state.SendTypeChars("Sys.") @@ -5226,7 +5213,7 @@ class C provider.Reset() ' Switch to the blocking mode - globalOptions.SetGlobalOption(New OptionKey(CompletionViewOptions.BlockForCompletionItems, LanguageNames.CSharp), True) + globalOptions.SetGlobalOption(CompletionViewOptions.BlockForCompletionItems, LanguageNames.CSharp, True) #Disable Warning BC42358 ' Because this call is not awaited, execution of the current method continues before the call is completed Task.Run(Function() @@ -5470,8 +5457,7 @@ class Program , showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp, True) state.SendBackspace() Await state.AssertSelectedCompletionItem(displayText:="Environment", isHardSelected:=True) @@ -5873,8 +5859,7 @@ class C } ) - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp, True) state.SendTypeChars("""") @@ -6121,8 +6106,7 @@ public class Program , showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp, True) state.SendInvokeCompletionList() state.SendBackspace() @@ -6146,8 +6130,7 @@ public class Program , showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp, True) state.SendInvokeCompletionList() state.SelectAndMoveCaret(-6) @@ -6195,8 +6178,7 @@ class C }, showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp, True) state.SendBackspace() Await state.AssertCompletionItemsContainAll("WriteLine") @@ -6449,8 +6431,7 @@ class C , showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp, True) state.SendBackspace() Await state.AssertCompletionSession() @@ -6476,8 +6457,7 @@ class C , showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp, True) state.SendBackspace() Await state.AssertCompletionSession() @@ -6561,8 +6541,7 @@ class C Dim completionService = state.Workspace.Services.GetLanguageServices(LanguageNames.CSharp).GetRequiredService(Of CompletionService)() Dim provider = completionService.GetTestAccessor().GetImportedAndBuiltInProviders(ImmutableHashSet(Of String).Empty).OfType(Of IntelliCodeMockProvider)().Single() - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp, True) state.SendBackspace() Await state.AssertCompletionItemsContainAll("Normalize", "★ Normalize") @@ -6668,8 +6647,7 @@ class C Dim completionService = state.Workspace.Services.GetLanguageServices(LanguageNames.CSharp).GetRequiredService(Of CompletionService)() Dim provider = completionService.GetTestAccessor().GetImportedAndBuiltInProviders(ImmutableHashSet(Of String).Empty).OfType(Of IntelliCodeMockProvider)().Single() - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp, True) state.SendTypeChars(".nor") Await state.AssertCompletionItemsContainAll("Normalize", "★ Normalize") @@ -6719,8 +6697,7 @@ class C Dim completionService = state.Workspace.Services.GetLanguageServices(LanguageNames.CSharp).GetRequiredService(Of CompletionService)() Dim provider = completionService.GetTestAccessor().GetImportedAndBuiltInProviders(ImmutableHashSet(Of String).Empty).OfType(Of IntelliCodeMockProvider)().Single() - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp, True) state.SendTypeChars(".nor") Await state.AssertCompletionItemsContainAll("Normalize", "★ Normalize") @@ -6789,7 +6766,7 @@ namespace NS2 Dim completionService = document.GetLanguageService(Of CompletionService)() completionService.GetTestAccessor().SuppressPartialSemantics() - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True) Dim service = state.Workspace.Services.GetLanguageServices(LanguageNames.CSharp).GetRequiredService(Of ITypeImportCompletionService)() @@ -6838,7 +6815,7 @@ namespace NS2 ) Dim document = state.Workspace.CurrentSolution.GetDocument(state.Workspace.Documents.Single(Function(d) d.Name = "C.cs").Id) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True) Dim completionService = document.GetLanguageService(Of CompletionService)() completionService.GetTestAccessor().SuppressPartialSemantics() @@ -6878,7 +6855,7 @@ namespace NS2 ]]>, showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation, True) ' trigger completion with import completion disabled Await state.SendInvokeCompletionListAndWaitForUiRenderAsync() @@ -6937,8 +6914,8 @@ namespace NS2 ]]>, showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation), True) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation, True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True) ' trigger completion with import completion enabled Await state.SendInvokeCompletionListAndWaitForUiRenderAsync() @@ -6974,8 +6951,8 @@ namespace NS1 ]]>, showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation), True) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation, True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True) ' trigger completion with import completion enabled Await state.SendInvokeCompletionListAndWaitForUiRenderAsync() @@ -7013,8 +6990,8 @@ public class AA }) state.TextView.Options.SetOptionValue(DefaultOptions.ResponsiveCompletionOptionId, True) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation), True) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation, True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True) Await state.SendInvokeCompletionListAndWaitForUiRenderAsync() @@ -7058,7 +7035,7 @@ public class AA } }) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation, True) Await state.SendInvokeCompletionListAndWaitForUiRenderAsync() @@ -7493,8 +7470,8 @@ namespace NS2 } " - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation), True) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation, True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True) Await state.SendInvokeCompletionListAndWaitForUiRenderAsync() @@ -7559,8 +7536,8 @@ namespace NS2 } " - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation), True) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation, True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True) Await state.SendInvokeCompletionListAndWaitForUiRenderAsync() @@ -7625,8 +7602,8 @@ namespace NS2 } " - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation), True) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation, True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True) Await state.SendInvokeCompletionListAndWaitForUiRenderAsync() @@ -7691,8 +7668,8 @@ namespace NS2 } " - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation), True) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation, True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True) Await state.SendInvokeCompletionListAndWaitForUiRenderAsync() @@ -7758,8 +7735,8 @@ namespace NS2 } " - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation), True) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation, True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True) Await state.SendInvokeCompletionListAndWaitForUiRenderAsync() @@ -7794,8 +7771,8 @@ namespace OtherNS , showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation), True) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation, True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True) Await state.SendInvokeCompletionListAndWaitForUiRenderAsync() @@ -7883,20 +7860,17 @@ namespace NS2 , showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation), True) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation, True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True) - ' trigger completion with import completion disabled Await state.SendInvokeCompletionListAndWaitForUiRenderAsync() ' make sure expander is selected - Await state.SetCompletionItemExpanderStateAndWaitForUiRenderAsync(isSelected:=True) + state.AssertCompletionItemExpander(isAvailable:=True, isSelected:=True) state.SendEscape() Await state.AssertNoCompletionSession() - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) - state.SendTypeChars("mytask") Await state.WaitForAsynchronousOperationsAsync() @@ -7938,8 +7912,7 @@ namespace NS ]]>, showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionOptionsStorage.ShowNameSuggestions, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ShowNameSuggestions, LanguageNames.CSharp, True) state.SendInvokeCompletionList() Await state.AssertCompletionItemsContainAll("foo123Bar", "foo123", "foo", "bar") @@ -7968,8 +7941,7 @@ namespace NS ]]>, showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionOptionsStorage.ShowNameSuggestions, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ShowNameSuggestions, LanguageNames.CSharp, True) state.SendInvokeCompletionList() Await state.AssertCompletionItemsContainAll("foo123", "foo") @@ -8442,8 +8414,8 @@ namespace B } } ) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation), True) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation, True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True) state.SendInvokeCompletionList() state.AssertItemsInOrder(New String() { @@ -8757,8 +8729,8 @@ public class AA }, showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation), True) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation, True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True) Dim expectedText = $" using CC; @@ -8803,8 +8775,8 @@ public class AA } }, showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation), True) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation, True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True) Await state.SendInvokeCompletionListAndWaitForUiRenderAsync() @@ -8853,9 +8825,8 @@ public class AA }, showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation), True) - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation, True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True) Await state.SendInvokeCompletionListAndWaitForUiRenderAsync() @@ -8907,9 +8878,8 @@ namespace Test , showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation), True) - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation, True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True) state.SendInvokeCompletionList() Await state.WaitForAsynchronousOperationsAsync() @@ -8958,9 +8928,8 @@ namespace MyNamespace , showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation), True) - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation, True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True) state.SendInvokeCompletionList() Await state.WaitForAsynchronousOperationsAsync() @@ -9000,9 +8969,8 @@ public class AA }, showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation), True) - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation, True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True) Await state.SendInvokeCompletionListAndWaitForUiRenderAsync() @@ -9039,9 +9007,8 @@ public class AA }, showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation), True) - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation, True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True) Await state.SendInvokeCompletionListAndWaitForUiRenderAsync() @@ -9085,9 +9052,8 @@ namespace Bar1 }, showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation), True) - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation, True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True) Await state.SendInvokeCompletionListAndWaitForUiRenderAsync() @@ -9131,9 +9097,8 @@ public unsafe class AA }, showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation), True) - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation, True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True) Await state.SendInvokeCompletionListAndWaitForUiRenderAsync() @@ -9494,8 +9459,7 @@ class C }]]>, showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp, True) state.SendBackspace() Await state.AssertSelectedCompletionItem("xml", isSoftSelected:=True).ConfigureAwait(True) @@ -9549,8 +9513,7 @@ class Repro extraExportedTypes:={GetType(PreselectionProvider)}.ToList(), showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp, True) state.SendInvokeCompletionList() Await state.AssertCompletionItemsContainAll({"★ length", "length", "Length"}) @@ -10200,8 +10163,8 @@ class C Dim workspace = state.Workspace Dim globalOptions = workspace.GetService(Of IGlobalOptionService) - globalOptions.SetGlobalOption(New OptionKey(CompletionViewOptions.BlockForCompletionItems, LanguageNames.CSharp), True) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) + globalOptions.SetGlobalOption(CompletionViewOptions.BlockForCompletionItems, LanguageNames.CSharp, True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True) state.TextView.Options.SetOptionValue(DefaultOptions.ResponsiveCompletionOptionId, True) @@ -10255,8 +10218,8 @@ class C Dim workspace = state.Workspace Dim globalOptions = workspace.GetService(Of IGlobalOptionService) - globalOptions.SetGlobalOption(New OptionKey(CompletionViewOptions.BlockForCompletionItems, LanguageNames.CSharp), True) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) + globalOptions.SetGlobalOption(CompletionViewOptions.BlockForCompletionItems, LanguageNames.CSharp, True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True) state.TextView.Options.SetOptionValue(DefaultOptions.ResponsiveCompletionOptionId, True) @@ -10308,9 +10271,9 @@ class C Dim workspace = state.Workspace Dim globalOptions = workspace.GetService(Of IGlobalOptionService) - globalOptions.SetGlobalOption(New OptionKey(CompletionViewOptions.BlockForCompletionItems, LanguageNames.CSharp), True) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation), True) + globalOptions.SetGlobalOption(CompletionViewOptions.BlockForCompletionItems, LanguageNames.CSharp, True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation, True) state.TextView.Options.SetOptionValue(DefaultOptions.ResponsiveCompletionOptionId, True) @@ -10625,7 +10588,7 @@ class MyClass } ) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowNewSnippetExperienceUserOption, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ShowNewSnippetExperienceUserOption, LanguageNames.CSharp, True) state.SendTypeChars("if") Await state.AssertSelectedCompletionItem(displayText:="if", inlineDescription:=Nothing, isHardSelected:=True) state.SendDownKey() @@ -10699,7 +10662,7 @@ class MyClass } ) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowNewSnippetExperienceUserOption, LanguageNames.CSharp), False) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ShowNewSnippetExperienceUserOption, LanguageNames.CSharp, False) state.SendInvokeCompletionList() ' We should still work normally w/o pythia recommender Await state.AssertCompletionItemsContainAll("argumentException", "exception") @@ -10722,7 +10685,7 @@ class MyClass , extraExportedTypes:={GetType(TestPythiaDeclarationNameRecommenderImplmentation)}.ToList()) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowNewSnippetExperienceUserOption, LanguageNames.CSharp), False) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ShowNewSnippetExperienceUserOption, LanguageNames.CSharp, False) state.SendInvokeCompletionList() Dim computedItems = (Await state.GetCompletionSession()).GetComputedItems(CancellationToken.None) @@ -11066,5 +11029,25 @@ public class Bar<T> : ISomeInterface<T> Await state.AssertCompletionItemsContain("SomeExtMethod", displayTextSuffix:="<>") End Using End Function + + + Public Async Function TestAsyncMethodReturningValueTask() As Task + Using state = TestStateFactory.CreateCSharpTestState( + +using System.Threading.Tasks; + +class Program +{ + async ValueTask<string> M2Async() + { + return new $$; + } +} + ) + + state.SendInvokeCompletionList() + Await state.AssertCompletionItemsContain("string", displayTextSuffix:="") + End Using + End Function End Class End Namespace diff --git a/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests_DefaultsSource.vb b/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests_DefaultsSource.vb index db0cccd35b35a..11ebe4204fe8e 100644 --- a/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests_DefaultsSource.vb +++ b/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests_DefaultsSource.vb @@ -3,8 +3,12 @@ ' See the LICENSE file in the project root for more information. Imports System.Collections.Immutable +Imports System.Composition +Imports Microsoft.CodeAnalysis.Completion Imports Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.AsyncCompletion Imports Microsoft.CodeAnalysis.Host.Mef +Imports Microsoft.CodeAnalysis.Options +Imports Microsoft.CodeAnalysis.Text Imports Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion Imports Microsoft.VisualStudio.Text.Editor @@ -13,8 +17,8 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense Public Class CSharpCompletionCommandHandlerTests_DefaultsSource - - Public Async Function TestNoItemMatchesDefaults(isAggressive As Boolean) As Task + + Public Async Function TestNoItemMatchesDefaults() As Task ' We are not adding the additional file which contains type MyAB and MyA ' the the suggestion from default source doesn't match anything in the completion list. Using state = TestStateFactory.CreateCSharpTestState( @@ -29,10 +33,6 @@ class C , extraExportedTypes:={GetType(MockDefaultSource)}.ToList()) - If isAggressive Then - state.TextView.Options.SetOptionValue(ItemManager.AggressiveDefaultsMatchingOptionName, True) - End If - state.SendInvokeCompletionList() Await state.AssertCompletionItemsDoNotContainAny("MyAB", "MyA") @@ -127,8 +127,8 @@ class My End Using End Function - - Public Async Function DoNotChangeIfPreselection(isAggressive As Boolean) As Task + + Public Async Function DoNotChangeIfPreselection() As Task Using state = CreateTestStateWithAdditionalDocument( using NS1; @@ -140,9 +140,6 @@ class C } } ) - If isAggressive Then - state.TextView.Options.SetOptionValue(ItemManager.AggressiveDefaultsMatchingOptionName, True) - End If state.SendInvokeCompletionList() @@ -154,6 +151,7 @@ class C End Function Private Shared Function CreateTestStateWithAdditionalDocument(documentElement As XElement) As TestState + MockDefaultSource.Defaults = ImmutableArray.Create("MyAB", "MyA") Return TestStateFactory.CreateTestStateFromWorkspace( @@ -186,14 +184,112 @@ namespace NS1 Private Class MockDefaultSource Implements IAsyncCompletionDefaultsSource + Public Shared Defaults As ImmutableArray(Of String) = ImmutableArray(Of String).Empty + Public Sub New() End Sub Public Function GetSessionDefaultsAsync(session As IAsyncCompletionSession) As Task(Of ImmutableArray(Of String)) Implements IAsyncCompletionDefaultsSource.GetSessionDefaultsAsync - Return Task.FromResult(ImmutableArray.Create("MyAB", "MyA")) + Return Task.FromResult(Defaults) + End Function + End Class + + + Public Async Function SelectDefaultItemOverStarredItem() As Task + Using state = TestStateFactory.CreateCSharpTestState( + +class MyClass +{ + public bool FirstStarred() => true; + public bool SecondStarred() => true; + public bool FirstDefault() => true; +} +class Test +{ + void M(MyClass c) + { + c$$ + } +} + , + extraExportedTypes:={GetType(IntelliCodeMockProvider), GetType(MockDefaultSource)}.ToList()) + + MockDefaultSource.Defaults = ImmutableArray.Create("FirstDefault") + state.SendTypeChars(".") + + Await state.AssertCompletionItemsContainAll("★ FirstStarred", "★ SecondStarred", "FirstStarred", "SecondStarred", "FirstDefault") + Await state.AssertSelectedCompletionItem("FirstDefault", isHardSelected:=True) + + state.SendTypeChars("First") + Await state.AssertCompletionItemsContainAll("★ FirstStarred", "FirstStarred", "FirstDefault") + Await state.AssertSelectedCompletionItem("FirstDefault", isHardSelected:=True) + + state.SendTypeChars("S") + Await state.AssertSelectedCompletionItem("★ FirstStarred", isHardSelected:=True) + End Using + End Function + + + Public Async Function SelectStarredItemInDefaultList() As Task + Using state = TestStateFactory.CreateCSharpTestState( + +class MyClass +{ + public bool FirstStarred() => true; + public bool SecondStarred() => true; + public bool FirstDefault() => true; +} +class Test +{ + void M(MyClass c) + { + c$$ + } +} + , + extraExportedTypes:={GetType(IntelliCodeMockProvider), GetType(MockDefaultSource)}.ToList()) + + MockDefaultSource.Defaults = ImmutableArray.Create("SecondStarred") + state.SendTypeChars(".") + + Await state.AssertCompletionItemsContainAll("★ FirstStarred", "★ SecondStarred", "FirstStarred", "SecondStarred", "FirstDefault") + Await state.AssertSelectedCompletionItem("★ SecondStarred", isHardSelected:=True) + + state.SendTypeChars("starred") + Await state.AssertCompletionItemsContainAll("★ FirstStarred", "FirstStarred", "★ SecondStarred", "SecondStarred") + Await state.AssertSelectedCompletionItem("★ SecondStarred", isHardSelected:=True) + End Using + End Function + + + <[Shared]> + + Private Class IntelliCodeMockProvider + Inherits CompletionProvider + + + + Public Sub New() + End Sub + + Public Overrides Function ProvideCompletionsAsync(context As CompletionContext) As Task + Dim rules = CompletionItemRules.Default.WithSelectionBehavior(CompletionItemSelectionBehavior.HardSelection).WithMatchPriority(MatchPriority.Preselect) + context.AddItem(CompletionItem.Create(displayText:="★ FirstStarred", filterText:="FirstStarred", sortText:=GetSortText(1), rules:=rules)) + context.AddItem(CompletionItem.Create(displayText:="★ SecondStarred", filterText:="SecondStarred", sortText:=GetSortText(2), rules:=rules)) + Return Task.CompletedTask + End Function + + ' This is what Pythia uses to sort starred items to the top of completion list + Private Shared Function GetSortText(index As Integer) As String + Return "!" + index.ToString("D10") + End Function + + Public Overrides Function ShouldTriggerCompletion(text As SourceText, caretPosition As Integer, trigger As CompletionTrigger, options As OptionSet) As Boolean + Return True End Function End Class + End Class End Namespace diff --git a/src/EditorFeatures/Test2/IntelliSense/CSharpSignatureHelpCommandHandlerTests.vb b/src/EditorFeatures/Test2/IntelliSense/CSharpSignatureHelpCommandHandlerTests.vb index 8b2105f977114..1739af2be3bad 100644 --- a/src/EditorFeatures/Test2/IntelliSense/CSharpSignatureHelpCommandHandlerTests.vb +++ b/src/EditorFeatures/Test2/IntelliSense/CSharpSignatureHelpCommandHandlerTests.vb @@ -884,7 +884,7 @@ class C , showCompletionInArgumentLists:=showCompletionInArgumentLists) ' disable implicit sig help then type a trigger character -> no session should be available - state.Workspace.GetService(Of IGlobalOptionService).SetGlobalOption(New OptionKey(SignatureHelpViewOptionsStorage.ShowSignatureHelp, LanguageNames.CSharp), False) + state.Workspace.GetService(Of IGlobalOptionService).SetGlobalOption(SignatureHelpViewOptionsStorage.ShowSignatureHelp, LanguageNames.CSharp, False) state.SendTypeChars("(") Await state.AssertNoSignatureHelpSession() diff --git a/src/EditorFeatures/Test2/IntelliSense/CompletionServiceTests.vb b/src/EditorFeatures/Test2/IntelliSense/CompletionServiceTests.vb index a1e7d40cb6028..7bc7451a3154f 100644 --- a/src/EditorFeatures/Test2/IntelliSense/CompletionServiceTests.vb +++ b/src/EditorFeatures/Test2/IntelliSense/CompletionServiceTests.vb @@ -37,7 +37,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense Dim completionService = New TestCompletionService(workspace.Services.SolutionServices, workspace.GetService(Of IAsynchronousOperationListenerProvider)()) Dim list = Await completionService.GetCompletionsAsync( - document, caretPosition:=0, CompletionOptions.Default, OptionValueSet.Empty, CompletionTrigger.Invoke) + document, caretPosition:=0, CompletionOptions.Default, OptionSet.Empty, CompletionTrigger.Invoke) Assert.NotEmpty(list.ItemsList) Assert.True(list.ItemsList.Count = 1, "Completion list contained more than one item") @@ -102,7 +102,7 @@ $$ Dim completionService = document.GetRequiredLanguageService(Of CompletionService)() Dim list = Await completionService.GetCompletionsAsync( - document, caretPosition:=0, CompletionOptions.Default, OptionValueSet.Empty, CompletionTrigger.Invoke, + document, caretPosition:=0, CompletionOptions.Default, OptionSet.Empty, CompletionTrigger.Invoke, roles:=ImmutableHashSet.Create("MyTextViewRole")) Assert.True(list.ItemsList.Contains(MyRoleProvider.Item)) diff --git a/src/EditorFeatures/Test2/IntelliSense/CompletionServiceTests_Exclusivitiy.vb b/src/EditorFeatures/Test2/IntelliSense/CompletionServiceTests_Exclusivitiy.vb index b000ee52f8e39..89346e8091914 100644 --- a/src/EditorFeatures/Test2/IntelliSense/CompletionServiceTests_Exclusivitiy.vb +++ b/src/EditorFeatures/Test2/IntelliSense/CompletionServiceTests_Exclusivitiy.vb @@ -42,7 +42,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense Dim completionService = New TestCompletionService(workspace.Services.SolutionServices) Dim list = Await completionService.GetCompletionsAsync( - document, caretPosition:=0, CompletionOptions.Default, OptionValueSet.Empty, CompletionTrigger.Invoke) + document, caretPosition:=0, CompletionOptions.Default, OptionSet.Empty, CompletionTrigger.Invoke) Assert.NotEmpty(list.ItemsList) Assert.True(list.ItemsList.Count = 2, "Completion List does not contain exactly two items.") diff --git a/src/EditorFeatures/Test2/IntelliSense/VisualBasicCompletionCommandHandlerTests.vb b/src/EditorFeatures/Test2/IntelliSense/VisualBasicCompletionCommandHandlerTests.vb index de4467351b3db..10eaf7ee4cd8d 100644 --- a/src/EditorFeatures/Test2/IntelliSense/VisualBasicCompletionCommandHandlerTests.vb +++ b/src/EditorFeatures/Test2/IntelliSense/VisualBasicCompletionCommandHandlerTests.vb @@ -1837,8 +1837,7 @@ Class Class1 End Class ) - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionOptionsStorage.EnterKeyBehavior, LanguageNames.VisualBasic), EnterKeyRule.AfterFullyTypedWord) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.EnterKeyBehavior, LanguageNames.VisualBasic, EnterKeyRule.AfterFullyTypedWord) state.SendTypeChars("System.TimeSpan.FromMin") state.SendReturn() @@ -1863,8 +1862,7 @@ Class Class1 End Class ) - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionOptionsStorage.EnterKeyBehavior, LanguageNames.VisualBasic), EnterKeyRule.AfterFullyTypedWord) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.EnterKeyBehavior, LanguageNames.VisualBasic, EnterKeyRule.AfterFullyTypedWord) state.SendTypeChars("System.TimeSpan.FromMinutes") state.SendReturn() @@ -2167,8 +2165,7 @@ Class G End Class ]]>) - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionOptionsStorage.TriggerOnTyping, LanguageNames.VisualBasic), False) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.TriggerOnTyping, LanguageNames.VisualBasic, False) state.SendBackspace() Await state.AssertNoCompletionSession() @@ -2656,8 +2653,7 @@ End Class }]]>, extraExportedTypes:={GetType(MockSnippetInfoService), GetType(SnippetCompletionProvider), GetType(StubVsEditorAdaptersFactoryService)}.ToList()) - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionOptionsStorage.SnippetsBehavior, LanguageNames.VisualBasic), SnippetsRule.AlwaysInclude) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.SnippetsBehavior, LanguageNames.VisualBasic, SnippetsRule.AlwaysInclude) state.SendTypeChars("Shortcu") Await state.AssertNoCompletionSession() @@ -2678,8 +2674,7 @@ End Class }]]>, extraExportedTypes:={GetType(MockSnippetInfoService), GetType(SnippetCompletionProvider), GetType(StubVsEditorAdaptersFactoryService)}.ToList()) - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionOptionsStorage.SnippetsBehavior, LanguageNames.VisualBasic), SnippetsRule.AlwaysInclude) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.SnippetsBehavior, LanguageNames.VisualBasic, SnippetsRule.AlwaysInclude) state.SendTypeChars("Shortcu") Await state.AssertNoCompletionSession() @@ -2701,8 +2696,7 @@ End Class }]]>, extraExportedTypes:={GetType(MockSnippetInfoService), GetType(SnippetCompletionProvider), GetType(StubVsEditorAdaptersFactoryService)}.ToList()) - state.Workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CompletionOptionsStorage.SnippetsBehavior, LanguageNames.VisualBasic), SnippetsRule.AlwaysInclude) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.SnippetsBehavior, LanguageNames.VisualBasic, SnippetsRule.AlwaysInclude) state.SendInvokeCompletionList() Await state.AssertCompletionItemsContainAll("x", "Shortcut") diff --git a/src/EditorFeatures/Test2/IntelliSense/VisualBasicSignatureHelpCommandHandlerTests.vb b/src/EditorFeatures/Test2/IntelliSense/VisualBasicSignatureHelpCommandHandlerTests.vb index 898f60a893da0..075fb68fceb86 100644 --- a/src/EditorFeatures/Test2/IntelliSense/VisualBasicSignatureHelpCommandHandlerTests.vb +++ b/src/EditorFeatures/Test2/IntelliSense/VisualBasicSignatureHelpCommandHandlerTests.vb @@ -284,7 +284,7 @@ End Class ) ' disable implicit sig help then type a trigger character -> no session should be available - state.Workspace.GetService(Of IGlobalOptionService).SetGlobalOption(New OptionKey(SignatureHelpViewOptionsStorage.ShowSignatureHelp, LanguageNames.VisualBasic), False) + state.Workspace.GetService(Of IGlobalOptionService).SetGlobalOption(SignatureHelpViewOptionsStorage.ShowSignatureHelp, LanguageNames.VisualBasic, False) state.SendTypeChars("(") Await state.AssertNoSignatureHelpSession() diff --git a/src/EditorFeatures/Test2/KeywordHighlighting/AbstractKeywordHighlightingTests.vb b/src/EditorFeatures/Test2/KeywordHighlighting/AbstractKeywordHighlightingTests.vb index a4b5f43111696..c7199c09b32db 100644 --- a/src/EditorFeatures/Test2/KeywordHighlighting/AbstractKeywordHighlightingTests.vb +++ b/src/EditorFeatures/Test2/KeywordHighlighting/AbstractKeywordHighlightingTests.vb @@ -28,7 +28,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.KeywordHighlighting Dim document As Document = workspace.CurrentSolution.Projects.First.Documents.First Dim globalOptions = workspace.GetService(Of IGlobalOptionService) - globalOptions.SetGlobalOption(New OptionKey(FeatureOnOffOptions.KeywordHighlighting, document.Project.Language), optionIsEnabled) + globalOptions.SetGlobalOption(FeatureOnOffOptions.KeywordHighlighting, document.Project.Language, optionIsEnabled) WpfTestRunner.RequireWpfFact($"{NameOf(AbstractKeywordHighlightingTests)}.{NameOf(Me.VerifyHighlightsAsync)} creates asynchronous taggers") diff --git a/src/EditorFeatures/Test2/ReferenceHighlighting/AbstractReferenceHighlightingTests.vb b/src/EditorFeatures/Test2/ReferenceHighlighting/AbstractReferenceHighlightingTests.vb index c05cf89d81d92..21892cc3b3029 100644 --- a/src/EditorFeatures/Test2/ReferenceHighlighting/AbstractReferenceHighlightingTests.vb +++ b/src/EditorFeatures/Test2/ReferenceHighlighting/AbstractReferenceHighlightingTests.vb @@ -37,7 +37,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.ReferenceHighlighting Dim caretPosition = hostDocument.CursorPosition.Value Dim snapshot = hostDocument.GetTextBuffer().CurrentSnapshot - globalOptions.SetGlobalOption(New OptionKey(FeatureOnOffOptions.ReferenceHighlighting, hostDocument.Project.Language), optionIsEnabled) + globalOptions.SetGlobalOption(FeatureOnOffOptions.ReferenceHighlighting, hostDocument.Project.Language, optionIsEnabled) Dim document = workspace.CurrentSolution.GetDocument(hostDocument.Id) Dim context = New TaggerContext(Of NavigableHighlightTag)( diff --git a/src/EditorFeatures/Test2/Rename/InlineRenameTests.vb b/src/EditorFeatures/Test2/Rename/InlineRenameTests.vb index 9f64c64f4cfb0..f1fc6b752d873 100644 --- a/src/EditorFeatures/Test2/Rename/InlineRenameTests.vb +++ b/src/EditorFeatures/Test2/Rename/InlineRenameTests.vb @@ -126,7 +126,7 @@ class [|Test1$$|] , host) Dim globalOptions = workspace.GetService(Of IGlobalOptionService)() - globalOptions.SetGlobalOption(New OptionKey(InlineRenameSessionOptionsStorage.RenameFile), True) + globalOptions.SetGlobalOption(InlineRenameSessionOptionsStorage.RenameFile, True) Dim session = StartSession(workspace) @@ -246,10 +246,10 @@ class Deconstructable Optional fileToRename As DocumentId = Nothing) As Task Dim globalOptions = workspace.GetService(Of IGlobalOptionService)() - globalOptions.SetGlobalOption(New OptionKey(InlineRenameSessionOptionsStorage.RenameOverloads), renameOverloads) - globalOptions.SetGlobalOption(New OptionKey(InlineRenameSessionOptionsStorage.RenameInStrings), renameInStrings) - globalOptions.SetGlobalOption(New OptionKey(InlineRenameSessionOptionsStorage.RenameInComments), renameInComments) - globalOptions.SetGlobalOption(New OptionKey(InlineRenameSessionOptionsStorage.RenameFile), renameFile) + globalOptions.SetGlobalOption(InlineRenameSessionOptionsStorage.RenameOverloads, renameOverloads) + globalOptions.SetGlobalOption(InlineRenameSessionOptionsStorage.RenameInStrings, renameInStrings) + globalOptions.SetGlobalOption(InlineRenameSessionOptionsStorage.RenameInComments, renameInComments) + globalOptions.SetGlobalOption(InlineRenameSessionOptionsStorage.RenameFile, renameFile) Dim session = StartSession(workspace) @@ -2102,5 +2102,46 @@ class [|C|] End Using End Function + + + + Public Async Function RenameWithGeneratedFile(host As RenameTestHost) As Task + Using workspace = CreateWorkspaceWithWaiter( + + + + partial class [|$$MyClass|] + { + public void M1() + { + } + } + + + partial class [|MyClass|] + { + public void M2() + { + } + } + + + , host) + + Dim session = StartSession(workspace) + + ' Type a bit in the file + Dim cursorDocument = workspace.Documents.Single(Function(d) d.CursorPosition.HasValue) + Dim caretPosition = cursorDocument.CursorPosition.Value + Dim textBuffer = cursorDocument.GetTextBuffer() + + textBuffer.Insert(caretPosition, "Example") + + session.Commit() + + Await VerifyTagsAreCorrect(workspace) + End Using + End Function + End Class End Namespace diff --git a/src/EditorFeatures/Test2/Rename/RenameCommandHandlerTests.vb b/src/EditorFeatures/Test2/Rename/RenameCommandHandlerTests.vb index 64517f397eeb3..107a269acd118 100644 --- a/src/EditorFeatures/Test2/Rename/RenameCommandHandlerTests.vb +++ b/src/EditorFeatures/Test2/Rename/RenameCommandHandlerTests.vb @@ -235,7 +235,7 @@ End Class ' This test specifically matters for the case where a user is typing in the editor ' and is not intended to test the rename flyout tab behavior Dim optionsService = workspace.GetService(Of IGlobalOptionService)() - optionsService.SetGlobalOption(New OptionKey(InlineRenameUIOptions.UseInlineAdornment), False) + optionsService.SetGlobalOption(InlineRenameUIOptions.UseInlineAdornment, False) Dim view = workspace.Documents.Single().GetTextView() view.Caret.MoveTo(New SnapshotPoint(view.TextBuffer.CurrentSnapshot, workspace.Documents.Single(Function(d) d.CursorPosition.HasValue).CursorPosition.Value)) diff --git a/src/EditorFeatures/Test2/Rename/RenameViewModelTests.vb b/src/EditorFeatures/Test2/Rename/RenameViewModelTests.vb index c1b6c34549a3f..d1277e44211ce 100644 --- a/src/EditorFeatures/Test2/Rename/RenameViewModelTests.vb +++ b/src/EditorFeatures/Test2/Rename/RenameViewModelTests.vb @@ -552,10 +552,10 @@ class D : B Using workspace = CreateWorkspaceWithWaiter(test, host) Dim globalOptions = workspace.GetService(Of IGlobalOptionService)() - globalOptions.SetGlobalOption(New OptionKey(InlineRenameSessionOptionsStorage.RenameOverloads), renameOverloads) - globalOptions.SetGlobalOption(New OptionKey(InlineRenameSessionOptionsStorage.RenameInStrings), renameInStrings) - globalOptions.SetGlobalOption(New OptionKey(InlineRenameSessionOptionsStorage.RenameInComments), renameInComments) - globalOptions.SetGlobalOption(New OptionKey(InlineRenameSessionOptionsStorage.RenameFile), renameFile) + globalOptions.SetGlobalOption(InlineRenameSessionOptionsStorage.RenameOverloads, renameOverloads) + globalOptions.SetGlobalOption(InlineRenameSessionOptionsStorage.RenameInStrings, renameInStrings) + globalOptions.SetGlobalOption(InlineRenameSessionOptionsStorage.RenameInComments, renameInComments) + globalOptions.SetGlobalOption(InlineRenameSessionOptionsStorage.RenameFile, renameFile) Dim cursorDocument = workspace.Documents.Single(Function(d) d.CursorPosition.HasValue) Dim cursorPosition = cursorDocument.CursorPosition.Value @@ -694,7 +694,7 @@ class D : B Using workspace = CreateWorkspaceWithWaiter(test, host) Dim globalOptions = workspace.GetService(Of IGlobalOptionService)() - globalOptions.SetGlobalOption(New OptionKey(InlineRenameUIOptions.CollapseUI), False) + globalOptions.SetGlobalOption(InlineRenameUIOptions.CollapseUI, False) Dim cursorDocument = workspace.Documents.Single(Function(d) d.CursorPosition.HasValue) Dim renameService = DirectCast(workspace.GetService(Of IInlineRenameService)(), InlineRenameService) diff --git a/src/EditorFeatures/TestUtilities/Completion/AbstractCompletionProviderTests.cs b/src/EditorFeatures/TestUtilities/Completion/AbstractCompletionProviderTests.cs index cd792e7eacacf..39ebc2164e02f 100644 --- a/src/EditorFeatures/TestUtilities/Completion/AbstractCompletionProviderTests.cs +++ b/src/EditorFeatures/TestUtilities/Completion/AbstractCompletionProviderTests.cs @@ -131,7 +131,7 @@ internal Task GetCompletionListAsync( int position, RoslynCompletion.CompletionTrigger triggerInfo, CompletionOptions options = null) - => service.GetCompletionsAsync(document, position, options ?? GetCompletionOptions(), OptionValueSet.Empty, triggerInfo, GetRoles(document)); + => service.GetCompletionsAsync(document, position, options ?? GetCompletionOptions(), TestOptionSet.Empty, triggerInfo, GetRoles(document)); private protected async Task CheckResultsAsync( Document document, int position, string expectedItemOrNull, diff --git a/src/EditorFeatures/TestUtilities/Diagnostics/DiagnosticTaggerWrapper.cs b/src/EditorFeatures/TestUtilities/Diagnostics/DiagnosticTaggerWrapper.cs index 78d8b4b2d1667..50247ec4681e8 100644 --- a/src/EditorFeatures/TestUtilities/Diagnostics/DiagnosticTaggerWrapper.cs +++ b/src/EditorFeatures/TestUtilities/Diagnostics/DiagnosticTaggerWrapper.cs @@ -47,8 +47,8 @@ public DiagnosticTaggerWrapper( // Change the background analysis scope to OpenFiles instead of ActiveFile (default), // so that every diagnostic tagger test does not need to mark test files as "active" file. - workspace.GlobalOptions.SetGlobalOption(new OptionKey(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp), BackgroundAnalysisScope.OpenFiles); - workspace.GlobalOptions.SetGlobalOption(new OptionKey(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.VisualBasic), BackgroundAnalysisScope.OpenFiles); + workspace.GlobalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp, BackgroundAnalysisScope.OpenFiles); + workspace.GlobalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.VisualBasic, BackgroundAnalysisScope.OpenFiles); _workspace = workspace; diff --git a/src/EditorFeatures/TestUtilities/Formatting/AbstractNewDocumentFormattingServiceTests.cs b/src/EditorFeatures/TestUtilities/Formatting/AbstractNewDocumentFormattingServiceTests.cs index 61ed7700639f4..55112222f0057 100644 --- a/src/EditorFeatures/TestUtilities/Formatting/AbstractNewDocumentFormattingServiceTests.cs +++ b/src/EditorFeatures/TestUtilities/Formatting/AbstractNewDocumentFormattingServiceTests.cs @@ -33,7 +33,7 @@ internal async Task TestAsync(string testCode, string expected, OptionsCollectio var languageServices = document.Project.Services; var cleanupOptions = - options?.ToAnalyzerConfigOptions(languageServices).GetCodeCleanupOptions(allowImportsInHiddenRegions: false, fallbackOptions: null, languageServices) ?? + options?.GetCodeCleanupOptions(allowImportsInHiddenRegions: false, fallbackOptions: null, languageServices) ?? CodeCleanupOptions.GetDefault(languageServices); var formattingService = document.GetRequiredLanguageService(); diff --git a/src/EditorFeatures/TestUtilities/Formatting/CoreFormatterTestsBase.cs b/src/EditorFeatures/TestUtilities/Formatting/CoreFormatterTestsBase.cs index 167ec650842d6..8faa1570526b8 100644 --- a/src/EditorFeatures/TestUtilities/Formatting/CoreFormatterTestsBase.cs +++ b/src/EditorFeatures/TestUtilities/Formatting/CoreFormatterTestsBase.cs @@ -85,7 +85,7 @@ internal void TestIndentation( editorOptions.SetOptionValue(DefaultOptions.ConvertTabsToSpacesOptionId, !useTabs); // Remove once https://github.com/dotnet/roslyn/issues/62204 is fixed: - workspace.GlobalOptions.SetGlobalOption(new OptionKey(IndentationOptionsStorage.SmartIndent, document.Project.Language), indentStyle); + workspace.GlobalOptions.SetGlobalOption(IndentationOptionsStorage.SmartIndent, document.Project.Language, indentStyle); var snapshot = textBuffer.CurrentSnapshot; var bufferGraph = new Mock(MockBehavior.Strict); @@ -201,7 +201,7 @@ private protected async Task AssertFormatAsync(string expected, string code, IEn var formattingService = document.GetRequiredLanguageService(); var formattingOptions = (options != null) - ? formattingService.GetFormattingOptions(options.ToAnalyzerConfigOptions(document.Project.Services), fallbackOptions: null) + ? formattingService.GetFormattingOptions(options, fallbackOptions: null) : formattingService.DefaultOptions; var rules = formattingRuleProvider.CreateRule(documentSyntax, 0).Concat(Formatter.GetDefaultFormattingRules(document)); @@ -287,7 +287,7 @@ protected static void AssertFormatOnArbitraryNode(SyntaxNode node, string expect { using var workspace = new AdhocWorkspace(); var formattingService = workspace.Services.GetLanguageServices(node.Language).GetRequiredService(); - var options = formattingService.GetFormattingOptions(DictionaryAnalyzerConfigOptions.Empty, fallbackOptions: null); + var options = formattingService.GetFormattingOptions(StructuredAnalyzerConfigOptions.Empty, fallbackOptions: null); var result = Formatter.Format(node, workspace.Services.SolutionServices, options, CancellationToken.None); var actual = result.GetText().ToString(); diff --git a/src/EditorFeatures/TestUtilities/TaskList/AbstractTaskListTests.cs b/src/EditorFeatures/TestUtilities/TaskList/AbstractTaskListTests.cs index bd45ba8c75d6f..bab78f3a94eae 100644 --- a/src/EditorFeatures/TestUtilities/TaskList/AbstractTaskListTests.cs +++ b/src/EditorFeatures/TestUtilities/TaskList/AbstractTaskListTests.cs @@ -31,7 +31,7 @@ protected async Task TestAsync(string codeWithMarker, TestHost host) using var workspace = CreateWorkspace(codeWithMarker, host); var descriptors = TaskListOptions.Default.Descriptors; - workspace.GlobalOptions.SetGlobalOption(new OptionKey(TaskListOptionsStorage.Descriptors), descriptors); + workspace.GlobalOptions.SetGlobalOption(TaskListOptionsStorage.Descriptors, descriptors); var hostDocument = workspace.Documents.First(); var initialTextSnapshot = hostDocument.GetTextBuffer().CurrentSnapshot; diff --git a/src/EditorFeatures/TestUtilities2/Intellisense/TestStateFactory.vb b/src/EditorFeatures/TestUtilities2/Intellisense/TestStateFactory.vb index bced396833bfb..5919d389d0e9a 100644 --- a/src/EditorFeatures/TestUtilities2/Intellisense/TestStateFactory.vb +++ b/src/EditorFeatures/TestUtilities2/Intellisense/TestStateFactory.vb @@ -25,8 +25,8 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense excludedTypes, extraExportedTypes, includeFormatCommandHandler, workspaceKind:=Nothing) - testState.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.TriggerInArgumentLists, LanguageNames.CSharp), showCompletionInArgumentLists) - testState.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), False) + testState.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.TriggerInArgumentLists, LanguageNames.CSharp, showCompletionInArgumentLists) + testState.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, False) Return testState End Function @@ -44,7 +44,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense excludedTypes:=Nothing, extraExportedTypes, includeFormatCommandHandler:=False, workspaceKind:=Nothing) - testState.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.VisualBasic), False) + testState.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.VisualBasic, False) Return testState End Function @@ -57,8 +57,8 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense Dim testState = New TestState( workspaceElement, excludedTypes:=Nothing, extraExportedTypes, includeFormatCommandHandler:=False, workspaceKind) - testState.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.TriggerInArgumentLists, LanguageNames.CSharp), showCompletionInArgumentLists) - testState.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.VisualBasic), False) + testState.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.TriggerInArgumentLists, LanguageNames.CSharp, showCompletionInArgumentLists) + testState.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.VisualBasic, False) Return testState End Function diff --git a/src/EditorFeatures/VisualBasic/AddImports/VisualBasicAddImportPlacementOptionsStorage.vb b/src/EditorFeatures/VisualBasic/AddImports/VisualBasicAddImportPlacementOptionsStorage.vb deleted file mode 100644 index df0ba04561ecc..0000000000000 --- a/src/EditorFeatures/VisualBasic/AddImports/VisualBasicAddImportPlacementOptionsStorage.vb +++ /dev/null @@ -1,40 +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.Runtime.CompilerServices -Imports Microsoft.CodeAnalysis.AddImport -Imports Microsoft.CodeAnalysis.Editing -Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.Options - -Namespace Microsoft.CodeAnalysis.VisualBasic.AddImport - Friend Module VisualBasicAddImportPlacementOptionsStorage - - - Private NotInheritable Class Service - Implements IAddImportPlacementOptionsStorage - - - - Public Sub New() - - End Sub - - Public Function GetOptions(globalOptions As IGlobalOptionService) As AddImportPlacementOptions Implements IAddImportPlacementOptionsStorage.GetOptions - Return GetVisualBasicAddImportPlacementOptions(globalOptions) - End Function - End Class - - - Public Function GetVisualBasicAddImportPlacementOptions(globalOptions As IGlobalOptionService) As AddImportPlacementOptions - Return New AddImportPlacementOptions() With - { - .PlaceSystemNamespaceFirst = globalOptions.GetOption(GenerationOptions.PlaceSystemNamespaceFirst, LanguageNames.VisualBasic), - .UsingDirectivePlacement = AddImportPlacementOptions.Default.UsingDirectivePlacement, ' VB does not support imports in namespace declarations - .AllowInHiddenRegions = AddImportPlacementOptions.Default.AllowInHiddenRegions ' no global option available - } - End Function - End Module -End Namespace diff --git a/src/EditorFeatures/VisualBasic/CodeGeneration/VisualBasicCodeGenerationOptionsStorage.vb b/src/EditorFeatures/VisualBasic/CodeGeneration/VisualBasicCodeGenerationOptionsStorage.vb deleted file mode 100644 index c3cca6c92f631..0000000000000 --- a/src/EditorFeatures/VisualBasic/CodeGeneration/VisualBasicCodeGenerationOptionsStorage.vb +++ /dev/null @@ -1,31 +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 Microsoft.CodeAnalysis.CodeGeneration -Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.Options -Imports Microsoft.CodeAnalysis.VisualBasic.CodeGeneration - -Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration - Friend Module VisualBasicCodeGenerationOptionsStorage - - Private NotInheritable Class Service - Implements ICodeGenerationOptionsStorage - - - - Public Sub New() - End Sub - - Public Function GetOptions(globalOptions As IGlobalOptionService) As CodeGenerationOptions Implements ICodeGenerationOptionsStorage.GetOptions - Return New VisualBasicCodeGenerationOptions() With - { - .Common = globalOptions.GetCommonCodeGenerationOptions(LanguageNames.VisualBasic) - } - End Function - End Class - End Module -End Namespace - diff --git a/src/EditorFeatures/VisualBasic/CodeStyle/VisualBasicCodeStyleOptionsStorage.vb b/src/EditorFeatures/VisualBasic/CodeStyle/VisualBasicCodeStyleOptionsStorage.vb deleted file mode 100644 index 802e89d11ba90..0000000000000 --- a/src/EditorFeatures/VisualBasic/CodeStyle/VisualBasicCodeStyleOptionsStorage.vb +++ /dev/null @@ -1,39 +0,0 @@ -' Licensed to the .NET Foundation under one or more agreements. -' The .NET Foundation licenses this file to you under the MIT license. -' See the LICENSE file in the project root for more information. - -Imports System.Composition -Imports System.Runtime.CompilerServices -Imports Microsoft.CodeAnalysis.CodeStyle -Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.Options -Imports Microsoft.CodeAnalysis.VisualBasic.CodeStyle - -Namespace Microsoft.CodeAnalysis.VisualBasic.CodeStyle - Friend Module VisualBasicCodeStyleOptionsStorage - - Private NotInheritable Class Service - Implements ICodeStyleOptionsStorage - - - - Public Sub New() - End Sub - - Public Function GetOptions(globalOptions As IGlobalOptionService) As IdeCodeStyleOptions Implements ICodeStyleOptionsStorage.GetOptions - Return GetVisualBasicCodeStyleOptions(globalOptions) - End Function - End Class - - - Public Function GetVisualBasicCodeStyleOptions(globalOptions As IGlobalOptionService) As VisualBasicIdeCodeStyleOptions - Return New VisualBasicIdeCodeStyleOptions( - Common:=globalOptions.GetCommonCodeStyleOptions(LanguageNames.VisualBasic), - PreferredModifierOrder:=globalOptions.GetOption(VisualBasicCodeStyleOptions.PreferredModifierOrder), - PreferIsNotExpression:=globalOptions.GetOption(VisualBasicCodeStyleOptions.PreferIsNotExpression), - PreferSimplifiedObjectCreation:=globalOptions.GetOption(VisualBasicCodeStyleOptions.PreferSimplifiedObjectCreation), - UnusedValueExpressionStatement:=globalOptions.GetOption(VisualBasicCodeStyleOptions.UnusedValueExpressionStatement), - UnusedValueAssignment:=globalOptions.GetOption(VisualBasicCodeStyleOptions.UnusedValueAssignment)) - End Function - End Module -End Namespace diff --git a/src/EditorFeatures/VisualBasic/Formatting/VisualBasicSyntaxFormattingOptionsStorage.vb b/src/EditorFeatures/VisualBasic/Formatting/VisualBasicSyntaxFormattingOptionsStorage.vb deleted file mode 100644 index eed0edbb5ef25..0000000000000 --- a/src/EditorFeatures/VisualBasic/Formatting/VisualBasicSyntaxFormattingOptionsStorage.vb +++ /dev/null @@ -1,36 +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.Runtime.CompilerServices -Imports Microsoft.CodeAnalysis.Formatting -Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.Options -Imports Microsoft.CodeAnalysis.VisualBasic.Formatting - -Namespace Microsoft.CodeAnalysis.VisualBasic.Formatting - Friend Module VisualBasicSyntaxFormattingOptionsStorage - - Private NotInheritable Class Service - Implements ISyntaxFormattingOptionsStorage - - - - Public Sub New() - End Sub - - Public Function GetOptions(globalOptions As IGlobalOptionService) As SyntaxFormattingOptions Implements ISyntaxFormattingOptionsStorage.GetOptions - Return GetVisualBasicSyntaxFormattingOptions(globalOptions) - End Function - End Class - - - Public Function GetVisualBasicSyntaxFormattingOptions(globalOptions As IGlobalOptionService) As VisualBasicSyntaxFormattingOptions - Return New VisualBasicSyntaxFormattingOptions() With - { - .Common = globalOptions.GetCommonSyntaxFormattingOptions(LanguageNames.VisualBasic) - } - End Function - End Module -End Namespace diff --git a/src/EditorFeatures/VisualBasic/Simplification/VisualBasicSimplifierOptionsStorage.vb b/src/EditorFeatures/VisualBasic/Simplification/VisualBasicSimplifierOptionsStorage.vb deleted file mode 100644 index 56d813862bc9d..0000000000000 --- a/src/EditorFeatures/VisualBasic/Simplification/VisualBasicSimplifierOptionsStorage.vb +++ /dev/null @@ -1,37 +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.Runtime.CompilerServices -Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.Options -Imports Microsoft.CodeAnalysis.Simplification -Imports Microsoft.CodeAnalysis.VisualBasic.Simplification - -Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification - Friend Module VisualBasicSimplifierOptionsStorage - - - Friend NotInheritable Class Service - Implements ISimplifierOptionsStorage - - - - Public Sub New() - End Sub - - Public Function GetOptions(globalOptions As IGlobalOptionService) As SimplifierOptions Implements ISimplifierOptionsStorage.GetOptions - Return GetVisualBasicSimplifierOptions(globalOptions) - End Function - End Class - - - Public Function GetVisualBasicSimplifierOptions(globalOptions As IGlobalOptionService) As VisualBasicSimplifierOptions - Return New VisualBasicSimplifierOptions() With - { - .Common = globalOptions.GetCommonSimplifierOptions(LanguageNames.VisualBasic) - } - End Function - End Module -End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/Diagnostics/AddImport/AddImportTests_NuGet.vb b/src/EditorFeatures/VisualBasicTest/Diagnostics/AddImport/AddImportTests_NuGet.vb index a1acadaf083fe..bac46d1601ff6 100644 --- a/src/EditorFeatures/VisualBasicTest/Diagnostics/AddImport/AddImportTests_NuGet.vb +++ b/src/EditorFeatures/VisualBasicTest/Diagnostics/AddImport/AddImportTests_NuGet.vb @@ -26,8 +26,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CodeActions.AddImp ImmutableArray.Create(New PackageSource(PackageSourceHelper.NugetOrgSourceName, "http://nuget.org")) Protected Overrides Sub InitializeWorkspace(workspace As TestWorkspace, parameters As TestParameters) - workspace.GlobalOptions.SetGlobalOption(New OptionKey(SymbolSearchOptionsStorage.SearchNuGetPackages, LanguageNames.VisualBasic), True) - workspace.GlobalOptions.SetGlobalOption(New OptionKey(SymbolSearchOptionsStorage.SearchReferenceAssemblies, LanguageNames.VisualBasic), True) + workspace.GlobalOptions.SetGlobalOption(SymbolSearchOptionsStorage.SearchNuGetPackages, LanguageNames.VisualBasic, True) + workspace.GlobalOptions.SetGlobalOption(SymbolSearchOptionsStorage.SearchReferenceAssemblies, LanguageNames.VisualBasic, True) End Sub Friend Overrides Function CreateDiagnosticProviderAndFixer(workspace As Workspace) As (DiagnosticAnalyzer, CodeFixProvider) diff --git a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/EndConstructCommandHandlerTests.vb b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/EndConstructCommandHandlerTests.vb index e3305c12b6684..332a1a8ae760a 100644 --- a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/EndConstructCommandHandlerTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/EndConstructCommandHandlerTests.vb @@ -13,11 +13,12 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera Public Class EndConstructCommandHandlerTests Private ReadOnly _endConstructServiceMock As New Mock(Of IEndConstructGenerationService)(MockBehavior.Strict) - Private ReadOnly _featureOptions As New Mock(Of ILegacyWorkspaceOptionService)(MockBehavior.Strict) 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() diff --git a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/EndConstructTestingHelpers.vb b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/EndConstructTestingHelpers.vb index b4c8432906d74..4602fce37138d 100644 --- a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/EndConstructTestingHelpers.vb +++ b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/EndConstructTestingHelpers.vb @@ -36,7 +36,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera Dim beforeText = before.Replace("$$", "") Using workspace = TestWorkspace.CreateVisualBasic(beforeText, composition:=EditorTestCompositions.EditorFeatures) Dim globalOptions = workspace.GetService(Of IGlobalOptionService) - globalOptions.SetGlobalOption(New OptionKey(FeatureOnOffOptions.PrettyListing, LanguageNames.VisualBasic), False) + globalOptions.SetGlobalOption(FeatureOnOffOptions.PrettyListing, LanguageNames.VisualBasic, False) Dim view = workspace.Documents.First().GetTextView() view.Caret.MoveTo(New SnapshotPoint(view.TextSnapshot, caretPos)) @@ -66,7 +66,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera afterCaret As Integer()) Using workspace = TestWorkspace.CreateVisualBasic(before, composition:=EditorTestCompositions.EditorFeatures) Dim globalOptions = workspace.GetService(Of IGlobalOptionService) - globalOptions.SetGlobalOption(New OptionKey(FeatureOnOffOptions.PrettyListing, LanguageNames.VisualBasic), False) + globalOptions.SetGlobalOption(FeatureOnOffOptions.PrettyListing, LanguageNames.VisualBasic, False) Dim textView = workspace.Documents.First().GetTextView() Dim subjectBuffer = workspace.Documents.First().GetTextBuffer() @@ -210,7 +210,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera ' create separate composition Using workspace = TestWorkspace.CreateVisualBasic(before, composition:=EditorTestCompositions.EditorFeatures) Dim globalOptions = workspace.GetService(Of IGlobalOptionService) - globalOptions.SetGlobalOption(New OptionKey(FeatureOnOffOptions.PrettyListing, LanguageNames.VisualBasic), False) + globalOptions.SetGlobalOption(FeatureOnOffOptions.PrettyListing, LanguageNames.VisualBasic, False) Dim view = workspace.Documents.First().GetTextView() view.Options.GlobalOptions.SetOptionValue(DefaultOptions.IndentStyleId, IndentingStyle.Smart) diff --git a/src/EditorFeatures/VisualBasicTest/Formatting/CodeCleanUpTests.vb b/src/EditorFeatures/VisualBasicTest/Formatting/CodeCleanUpTests.vb index f25897b21ef8a..0f36b52054da5 100644 --- a/src/EditorFeatures/VisualBasicTest/Formatting/CodeCleanUpTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Formatting/CodeCleanUpTests.vb @@ -568,8 +568,8 @@ End Class ' must set global options since incremental analyzer infra reads from global options Dim globalOptions = workspace.GlobalOptions - globalOptions.SetGlobalOption(New OptionKey(GenerationOptions.SeparateImportDirectiveGroups, LanguageNames.VisualBasic), separateImportsGroups) - globalOptions.SetGlobalOption(New OptionKey(GenerationOptions.PlaceSystemNamespaceFirst, LanguageNames.VisualBasic), systemImportsFirst) + globalOptions.SetGlobalOption(GenerationOptions.SeparateImportDirectiveGroups, LanguageNames.VisualBasic, separateImportsGroups) + globalOptions.SetGlobalOption(GenerationOptions.PlaceSystemNamespaceFirst, LanguageNames.VisualBasic, systemImportsFirst) Dim solution = workspace.CurrentSolution.WithAnalyzerReferences( { diff --git a/src/EditorFeatures/VisualBasicTest/Formatting/Indentation/SmartIndentProviderTests.vb b/src/EditorFeatures/VisualBasicTest/Formatting/Indentation/SmartIndentProviderTests.vb index 138fe23151c81..9a3b3e02ed6db 100644 --- a/src/EditorFeatures/VisualBasicTest/Formatting/Indentation/SmartIndentProviderTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Formatting/Indentation/SmartIndentProviderTests.vb @@ -40,7 +40,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Formatting.Indenta Public Sub GetSmartIndent3() Using workspace = TestWorkspace.CreateCSharp("") Dim globalOptions = workspace.GetService(Of IGlobalOptionService) - globalOptions.SetGlobalOption(New OptionKey(InternalFeatureOnOffOptions.SmartIndenter), False) + globalOptions.SetGlobalOption(InternalFeatureOnOffOptions.SmartIndenter, False) Dim document = workspace.Projects.Single().Documents.Single() Dim provider = workspace.ExportProvider.GetExportedValues(Of ISmartIndentProvider)().OfType(Of SmartIndentProvider)().Single() diff --git a/src/EditorFeatures/VisualBasicTest/ImplementInterface/ImplementInterfaceCommandHandlerTests.vb b/src/EditorFeatures/VisualBasicTest/ImplementInterface/ImplementInterfaceCommandHandlerTests.vb index 303c292e5848c..d0288ce16f35d 100644 --- a/src/EditorFeatures/VisualBasicTest/ImplementInterface/ImplementInterfaceCommandHandlerTests.vb +++ b/src/EditorFeatures/VisualBasicTest/ImplementInterface/ImplementInterfaceCommandHandlerTests.vb @@ -67,7 +67,7 @@ End Interface") Dim globalOptions = workspace.GetService(Of IGlobalOptionService) Dim commandHandler = MoveCaretAndCreateCommandHandler(workspace) - globalOptions.SetGlobalOption(New OptionKey(FeatureOnOffOptions.AutomaticInsertionOfAbstractOrInterfaceMembers, LanguageNames.VisualBasic), False) + globalOptions.SetGlobalOption(FeatureOnOffOptions.AutomaticInsertionOfAbstractOrInterfaceMembers, LanguageNames.VisualBasic, False) Dim nextHandlerCalled = False Dim view = workspace.Documents.Single().GetTextView() diff --git a/src/EditorFeatures/VisualBasicTest/LineCommit/CommitOnMiscellaneousCommandsTests.vb b/src/EditorFeatures/VisualBasicTest/LineCommit/CommitOnMiscellaneousCommandsTests.vb index a80a6c631b60e..b1f1e8e09e063 100644 --- a/src/EditorFeatures/VisualBasicTest/LineCommit/CommitOnMiscellaneousCommandsTests.vb +++ b/src/EditorFeatures/VisualBasicTest/LineCommit/CommitOnMiscellaneousCommandsTests.vb @@ -72,7 +72,7 @@ End Class Dim workspace = testData.Workspace Dim globalOptions = workspace.GetService(Of IGlobalOptionService) - globalOptions.SetGlobalOption(New OptionKey(FeatureOnOffOptions.PrettyListing, LanguageNames.VisualBasic), False) + globalOptions.SetGlobalOption(FeatureOnOffOptions.PrettyListing, LanguageNames.VisualBasic, False) testData.CommandHandler.ExecuteCommand(New PasteCommandArgs(testData.View, testData.Buffer), Sub() testData.EditorOperations.InsertText("Class Program" & vbCrLf & " Sub M(abc As Integer)" & vbCrLf & " Dim a = 7" & vbCrLf & " End Sub" & vbCrLf & "End Class"), @@ -131,7 +131,7 @@ End Class ) Dim workspace = testData.Workspace Dim globalOptions = workspace.GetService(Of IGlobalOptionService) - globalOptions.SetGlobalOption(New OptionKey(FeatureOnOffOptions.PrettyListing, LanguageNames.VisualBasic), False) + globalOptions.SetGlobalOption(FeatureOnOffOptions.PrettyListing, LanguageNames.VisualBasic, False) testData.Buffer.Insert(57, " ") testData.CommandHandler.ExecuteCommand(New SaveCommandArgs(testData.View, testData.Buffer), Sub() Exit Sub, TestCommandExecutionContext.Create()) @@ -180,7 +180,7 @@ End Module ' Turn off pretty listing Dim workspace = testData.Workspace Dim globalOptions = workspace.GetService(Of IGlobalOptionService) - globalOptions.SetGlobalOption(New OptionKey(FeatureOnOffOptions.PrettyListing, LanguageNames.VisualBasic), False) + globalOptions.SetGlobalOption(FeatureOnOffOptions.PrettyListing, LanguageNames.VisualBasic, False) testData.CommandHandler.ExecuteCommand(New FormatDocumentCommandArgs(testData.View, testData.Buffer), Sub() Exit Sub, TestCommandExecutionContext.Create()) Assert.Equal(" Sub Main()", testData.Buffer.CurrentSnapshot.GetLineFromLineNumber(1).GetText()) diff --git a/src/EditorFeatures/VisualBasicTest/Squiggles/ErrorSquiggleProducerTests.vb b/src/EditorFeatures/VisualBasicTest/Squiggles/ErrorSquiggleProducerTests.vb index 7b502cccfcd77..5535c6ea9e7b2 100644 --- a/src/EditorFeatures/VisualBasicTest/Squiggles/ErrorSquiggleProducerTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Squiggles/ErrorSquiggleProducerTests.vb @@ -119,8 +119,7 @@ End Class" Dim language = workspace.Projects.Single().Language workspace.GlobalOptions.SetGlobalOption( - New OptionKey(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration, language), - New CodeStyleOption2(Of Boolean)(value:=True, notification:=NotificationOption2.Error)) + CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration, language, New CodeStyleOption2(Of Boolean)(value:=True, notification:=NotificationOption2.Error)) Dim diagnosticsAndSpans = Await TestDiagnosticTagProducer(Of DiagnosticsSquiggleTaggerProvider, IErrorTag).GetDiagnosticsAndErrorSpans(workspace, analyzerMap) Dim spans = diagnosticsAndSpans.Item1.Zip(diagnosticsAndSpans.Item2, Function(diagnostic, span) (diagnostic, span)).OrderBy(Function(s) s.span.Span.Span.Start).ToImmutableArray() diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationContext.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationContext.cs index c20578c227afc..637ef3491ad0c 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationContext.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationContext.cs @@ -643,7 +643,7 @@ private EEMethodSymbol GetTypeVariablesMethod(EENamedTypeSymbol container, strin else if (expressionType.SpecialType == SpecialType.System_Void) { flags |= DkmClrCompilationResultFlags.ReadOnlyResult; - Debug.Assert(expression.ConstantValue == null); + Debug.Assert(expression.ConstantValueOpt == null); resultProperties = expression.ExpressionSymbol.GetResultProperties(flags, isConstant: false); return new BoundExpressionStatement(syntax, expression) { WasCompilerGenerated = true }; } @@ -657,7 +657,7 @@ private EEMethodSymbol GetTypeVariablesMethod(EENamedTypeSymbol container, strin flags |= DkmClrCompilationResultFlags.ReadOnlyResult; } - resultProperties = expression.ExpressionSymbol.GetResultProperties(flags, expression.ConstantValue != null); + resultProperties = expression.ExpressionSymbol.GetResultProperties(flags, expression.ConstantValueOpt != null); return new BoundReturnStatement(syntax, RefKind.None, expression, @checked: false) { WasCompilerGenerated = true }; } diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Rewriters/CapturedVariableRewriter.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Rewriters/CapturedVariableRewriter.cs index 8390abf31e13d..0bcaadd943ada 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Rewriters/CapturedVariableRewriter.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Rewriters/CapturedVariableRewriter.cs @@ -48,7 +48,7 @@ public override BoundNode VisitBlock(BoundBlock node) var rewrittenLocals = node.Locals.WhereAsArray((local, rewriter) => local.IsCompilerGenerated || local.Name == null || rewriter.GetVariable(local.Name) == null, this); var rewrittenLocalFunctions = node.LocalFunctions; var rewrittenStatements = VisitList(node.Statements); - return node.Update(rewrittenLocals, rewrittenLocalFunctions, rewrittenStatements); + return node.Update(rewrittenLocals, rewrittenLocalFunctions, node.HasUnsafeModifier, rewrittenStatements); } public override BoundNode VisitLocal(BoundLocal node) diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EELocalSymbolBase.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EELocalSymbolBase.cs index b43cf816751bb..992deaa441e9b 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EELocalSymbolBase.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EELocalSymbolBase.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Runtime.CompilerServices; using Microsoft.CodeAnalysis.CSharp.Symbols; using Roslyn.Utilities; @@ -52,7 +53,14 @@ internal override SyntaxNode ScopeDesignatorOpt get { return null; } } - internal sealed override LocalSymbol WithSynthesizedLocalKindAndSyntax(SynthesizedLocalKind kind, SyntaxNode syntax) + internal sealed override LocalSymbol WithSynthesizedLocalKindAndSyntax( + SynthesizedLocalKind kind, SyntaxNode syntax +#if DEBUG + , + [CallerLineNumber] int createdAtLineNumber = 0, + [CallerFilePath] string createdAtFilePath = null +#endif + ) { throw ExceptionUtilities.Unreachable(); } @@ -84,18 +92,6 @@ internal sealed override UseSiteInfo GetUseSiteInfo() return result; } - /// - /// EE Symbols have no source symbols associated with them. - /// They should be safe to escape for evaluation purposes. - /// - internal override uint ValEscapeScope => Binder.CurrentMethodScope; - - /// - /// EE Symbols have no source symbols associated with them. - /// They should be safe to escape for evaluation purposes. - /// - internal override uint RefEscapeScope => Binder.CurrentMethodScope; - - internal override DeclarationScope Scope => DeclarationScope.Unscoped; + internal override ScopedKind Scope => ScopedKind.None; } } diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EEMethodSymbol.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EEMethodSymbol.cs index 827504ab30293..d542811a49c76 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EEMethodSymbol.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EEMethodSymbol.cs @@ -188,7 +188,7 @@ internal EEMethodSymbol( private ParameterSymbol MakeParameterSymbol(int ordinal, string name, ParameterSymbol sourceParameter) { - return SynthesizedParameterSymbol.Create(this, sourceParameter.TypeWithAnnotations, ordinal, sourceParameter.RefKind, name, DeclarationScope.Unscoped, refCustomModifiers: sourceParameter.RefCustomModifiers); + return SynthesizedParameterSymbol.Create(this, sourceParameter.TypeWithAnnotations, ordinal, sourceParameter.RefKind, name, ScopedKind.None, refCustomModifiers: sourceParameter.RefCustomModifiers); } internal override bool IsMetadataNewSlot(bool ignoreInterfaceImplementationChanges = false) @@ -666,7 +666,7 @@ internal override void GenerateMethodBody(TypeCompilationState compilationState, localBuilder.Add(local); } - body = block.Update(localBuilder.ToImmutableAndFree(), block.LocalFunctions, block.Statements); + body = block.Update(localBuilder.ToImmutableAndFree(), block.LocalFunctions, block.HasUnsafeModifier, block.Statements); TypeParameterChecker.Check(body, _allTypeParameters); compilationState.AddSynthesizedMethod(this, body); } diff --git a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/CompileExpressionsTests.cs b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/CompileExpressionsTests.cs index 193c1a64371a3..81a065292467c 100644 --- a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/CompileExpressionsTests.cs +++ b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/CompileExpressionsTests.cs @@ -8,7 +8,9 @@ using System.Text; using Microsoft.CodeAnalysis.CodeGen; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.ExpressionEvaluator; using Microsoft.CodeAnalysis.ExpressionEvaluator.UnitTests; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; @@ -944,5 +946,192 @@ .maxstack 1 """); }); } + + [WorkItem(66109, "https://github.com/dotnet/roslyn/issues/66109")] + [Fact] + public void SequencePointsMultipleDocuments() + { + var sourceA = +@"partial class Program +{ + private int x = 1; + private void F() + { + } +}"; + var sourceB = +@"partial class Program +{ + private int y = 2; + public Program() + { + F(); + int z = x + y; + } +}"; + var comp = CreateCompilation( + new[] + { + SyntaxFactory.ParseSyntaxTree(sourceA, path: "A.cs", encoding: Encoding.Default), + SyntaxFactory.ParseSyntaxTree(sourceB, path: "B.cs", encoding: Encoding.Default) + }, + options: TestOptions.DebugDll); + + comp.VerifyPdb(""" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + """, + format: Microsoft.CodeAnalysis.Emit.DebugInformationFormat.Pdb); + comp.VerifyPdb(""" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + """, + format: Microsoft.CodeAnalysis.Emit.DebugInformationFormat.PortablePdb); + + // Disable testing with DebugInformationFormat.Pdb format for now (see https://github.com/dotnet/roslyn/issues/66260). + //WithRuntimeInstance( + // comp, + // references: null, + // includeLocalSignatures: true, + // includeIntrinsicAssembly: false, + // validator: runtime => + { + using (var runtime = RuntimeInstance.Create( + comp, + references: null, + Microsoft.CodeAnalysis.Emit.DebugInformationFormat.PortablePdb, + includeLocalSignatures: true, + includeIntrinsicAssembly: false)) + { + GetContextState(runtime, "Program..ctor", out var blocks, out var moduleVersionId, out var symReader, out var methodToken, out var localSignatureToken); + + var appDomain = new AppDomain(); + uint ilOffset = ExpressionCompilerTestHelpers.GetOffset(methodToken, symReader); + var context = CreateMethodContext( + appDomain, + blocks, + symReader, + moduleVersionId, + methodToken: methodToken, + methodVersion: 1, + ilOffset: 0x15, // offset matches startOffset of "z" scope + localSignatureToken: localSignatureToken, + kind: MakeAssemblyReferencesKind.AllAssemblies); + var testData = new CompilationTestData(); + var result = context.CompileExpression( + "z", + out var error, + testData); + Assert.Null(error); + Assert.NotNull(result.Assembly); + testData.GetMethodData("<>x.<>m0").VerifyIL(""" + { + // Code size 2 (0x2) + .maxstack 1 + .locals init (int V_0) //z + IL_0000: ldloc.0 + IL_0001: ret + } + """); + + testData = new CompilationTestData(); + var locals = ArrayBuilder.GetInstance(); + string typeName; + var assembly = context.CompileGetLocals(locals, argumentsOnly: false, typeName: out typeName, testData: testData); + + Assert.Equal(2, locals.Count); + VerifyLocal(testData, typeName, locals[0], "<>m0", "this", expectedILOpt: """ + { + // Code size 2 (0x2) + .maxstack 1 + .locals init (int V_0) //z + IL_0000: ldarg.0 + IL_0001: ret + } + """); + VerifyLocal(testData, typeName, locals[1], "<>m1", "z", expectedILOpt: """ + { + // Code size 2 (0x2) + .maxstack 1 + .locals init (int V_0) //z + IL_0000: ldloc.0 + IL_0001: ret + } + """); + } + } + } } } diff --git a/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/PDB/MethodDebugInfo.Native.cs b/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/PDB/MethodDebugInfo.Native.cs index 5fbdff49cfe5c..d3c14b025e954 100644 --- a/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/PDB/MethodDebugInfo.Native.cs +++ b/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/PDB/MethodDebugInfo.Native.cs @@ -59,7 +59,7 @@ public override int GetHashCode() public static unsafe MethodDebugInfo ReadMethodDebugInfo( ISymUnmanagedReader3? symReader, - EESymbolProvider? symbolProvider, // TODO: only null in DTEE case where we looking for default namesapace + EESymbolProvider? symbolProvider, // TODO: only null in DTEE case where we looking for default namespace int methodToken, int methodVersion, int ilOffset, @@ -175,13 +175,10 @@ public static unsafe MethodDebugInfo ReadMethodDebugI { // We need a receiver of type `ISymUnmanagedMethod` to call the extension `GetDocumentsForMethod()` here. // We also need to ensure that the receiver implements `ISymEncUnmanagedMethod` to prevent the extension from throwing. - var doc = methodInfo.GetDocumentsForMethod() switch + if (methodInfo.GetDocumentsForMethod() is [var singleDocument]) { - [var singleDocument] => singleDocument, - var documents => throw ExceptionUtilities.UnexpectedValue(documents) - }; - - name = doc.GetName(); + name = singleDocument.GetName(); + } } return new MethodDebugInfo( diff --git a/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/PDB/MethodDebugInfo.Portable.cs b/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/PDB/MethodDebugInfo.Portable.cs index deb656caa2f55..c1676464698f9 100644 --- a/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/PDB/MethodDebugInfo.Portable.cs +++ b/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/PDB/MethodDebugInfo.Portable.cs @@ -33,7 +33,7 @@ public static MethodDebugInfo ReadFromPortable( var methodHandle = GetDeltaRelativeMethodDefinitionHandle(reader, methodToken); - // TODO: only null in DTEE case where we looking for default namesapace + // TODO: only null in DTEE case where we looking for default namespace if (symbolProvider != null) { ReadLocalScopeInformation( @@ -64,8 +64,12 @@ public static MethodDebugInfo ReadFromPortable( ReadMethodCustomDebugInformation(reader, methodHandle, out var hoistedLocalScopes, out var defaultNamespace); var documentHandle = reader.GetMethodDebugInformation(methodHandle).Document; - var document = reader.GetDocument(documentHandle); - var documentName = reader.GetString(document.Name); + string? documentName = null; + if (!documentHandle.IsNil) + { + var document = reader.GetDocument(documentHandle); + documentName = reader.GetString(document.Name); + } return new MethodDebugInfo( hoistedLocalScopes, diff --git a/src/Features/CSharp/Portable/ConvertLinq/ConvertForEachToLinqQuery/AbstractToMethodConverter.cs b/src/Features/CSharp/Portable/ConvertLinq/ConvertForEachToLinqQuery/AbstractToMethodConverter.cs index 94e54adf2a8dd..365afe36fd3ec 100644 --- a/src/Features/CSharp/Portable/ConvertLinq/ConvertForEachToLinqQuery/AbstractToMethodConverter.cs +++ b/src/Features/CSharp/Portable/ConvertLinq/ConvertForEachToLinqQuery/AbstractToMethodConverter.cs @@ -189,7 +189,7 @@ protected InvocationExpressionSyntax CreateInvocationExpression(ExpressionSyntax => SyntaxFactory.InvocationExpression( SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, - SyntaxFactory.ParenthesizedExpression(queryOrLinqInvocationExpression), + queryOrLinqInvocationExpression.Parenthesize(), SyntaxFactory.IdentifierName(MethodName))).WithAdditionalAnnotations(Formatter.Annotation); } } diff --git a/src/Features/CSharp/Portable/ConvertLinq/ConvertForEachToLinqQuery/CSharpConvertForEachToLinqQueryProvider.cs b/src/Features/CSharp/Portable/ConvertLinq/ConvertForEachToLinqQuery/CSharpConvertForEachToLinqQueryProvider.cs index 10cb6ecad2b83..753ae6f0b4d4b 100644 --- a/src/Features/CSharp/Portable/ConvertLinq/ConvertForEachToLinqQuery/CSharpConvertForEachToLinqQueryProvider.cs +++ b/src/Features/CSharp/Portable/ConvertLinq/ConvertForEachToLinqQuery/CSharpConvertForEachToLinqQueryProvider.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections; using System.Collections.Generic; using System.Collections.Immutable; @@ -44,7 +42,7 @@ protected override ForEachInfo CreateFo var identifiersBuilder = ArrayBuilder.GetInstance(); identifiersBuilder.Add(forEachStatement.Identifier); var convertingNodesBuilder = ArrayBuilder.GetInstance(); - IEnumerable statementsCannotBeConverted = null; + IEnumerable? statementsCannotBeConverted = null; var trailingTokensBuilder = ArrayBuilder.GetInstance(); var currentLeadingTokens = ArrayBuilder.GetInstance(); @@ -213,7 +211,7 @@ protected override bool TryBuildSpecificConverter( SemanticModel semanticModel, StatementSyntax statementCannotBeConverted, CancellationToken cancellationToken, - out IConverter converter) + [NotNullWhen(true)] out IConverter? converter) { switch (statementCannotBeConverted.Kind()) { @@ -248,7 +246,7 @@ protected override bool TryBuildSpecificConverter( // Check that there is 'list.Add(item)'. if (invocationExpression.Expression is MemberAccessExpressionSyntax memberAccessExpression && semanticModel.GetSymbolInfo(memberAccessExpression, cancellationToken).Symbol is IMethodSymbol methodSymbol && - TypeSymbolOptIsList(methodSymbol.ContainingType, semanticModel) && + TypeSymbolIsList(methodSymbol.ContainingType, semanticModel) && methodSymbol.Name == nameof(IList.Add) && methodSymbol.Parameters.Length == 1 && invocationExpression.ArgumentList.Arguments.Count == 1) @@ -281,7 +279,7 @@ protected override bool TryBuildSpecificConverter( case SyntaxKind.YieldReturnStatement: var memberDeclarationSymbol = semanticModel.GetEnclosingSymbol( - forEachInfo.ForEachStatement.SpanStart, cancellationToken); + forEachInfo.ForEachStatement.SpanStart, cancellationToken)!; // Using Single() is valid even for partial methods. var memberDeclarationSyntax = memberDeclarationSymbol.DeclaringSyntaxReferences.Single().GetSyntax(); @@ -352,7 +350,7 @@ protected override SyntaxNode AddLinqUsing( return root; } - internal static bool TypeSymbolOptIsList(ITypeSymbol typeSymbol, SemanticModel semanticModel) - => Equals(typeSymbol?.OriginalDefinition, semanticModel.Compilation.GetTypeByMetadataName(typeof(List<>).FullName)); + internal static bool TypeSymbolIsList(ITypeSymbol typeSymbol, SemanticModel semanticModel) + => Equals(typeSymbol?.OriginalDefinition, semanticModel.Compilation.ListOfTType()); } } diff --git a/src/Features/CSharp/Portable/ConvertLinq/ConvertForEachToLinqQuery/ToToListConverter.cs b/src/Features/CSharp/Portable/ConvertLinq/ConvertForEachToLinqQuery/ToToListConverter.cs index 08bbf3bbb4c31..bba88d7c72e73 100644 --- a/src/Features/CSharp/Portable/ConvertLinq/ConvertForEachToLinqQuery/ToToListConverter.cs +++ b/src/Features/CSharp/Portable/ConvertLinq/ConvertForEachToLinqQuery/ToToListConverter.cs @@ -34,7 +34,7 @@ protected override bool CanReplaceInitialization( ExpressionSyntax expression, CancellationToken cancellationToken) => expression is ObjectCreationExpressionSyntax objectCreationExpression && ForEachInfo.SemanticModel.GetSymbolInfo(objectCreationExpression.Type, cancellationToken).Symbol is ITypeSymbol typeSymbol && - CSharpConvertForEachToLinqQueryProvider.TypeSymbolOptIsList(typeSymbol, ForEachInfo.SemanticModel) && + CSharpConvertForEachToLinqQueryProvider.TypeSymbolIsList(typeSymbol, ForEachInfo.SemanticModel) && (objectCreationExpression.ArgumentList == null || !objectCreationExpression.ArgumentList.Arguments.Any()) && (objectCreationExpression.Initializer == null || !objectCreationExpression.Initializer.Expressions.Any()); diff --git a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.cs b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.cs index e1c34d8cf553a..89a0f37262ccd 100644 --- a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.cs +++ b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.cs @@ -657,14 +657,24 @@ protected override StatementSyntax CreateDeclarationStatement( ExpressionSyntax initialValue, CancellationToken cancellationToken) { - var type = variable.GetVariableType(SemanticDocument); + var type = variable.GetVariableType(); var typeNode = type.GenerateTypeSyntax(); + var originalIdentifierToken = variable.GetOriginalIdentifierToken(cancellationToken); + + // Hierarchy being checked for to see if a using keyword is needed is + // Token -> VariableDeclarator -> VariableDeclaration -> LocalDeclaration + var usingKeyword = originalIdentifierToken.Parent?.Parent?.Parent is LocalDeclarationStatementSyntax { UsingKeyword.FullSpan.IsEmpty: false } + ? SyntaxFactory.Token(SyntaxKind.UsingKeyword) + : default; + var equalsValueClause = initialValue == null ? null : SyntaxFactory.EqualsValueClause(value: initialValue); return SyntaxFactory.LocalDeclarationStatement( SyntaxFactory.VariableDeclaration(typeNode) - .AddVariables(SyntaxFactory.VariableDeclarator(SyntaxFactory.Identifier(variable.Name)).WithInitializer(equalsValueClause))); + .AddVariables(SyntaxFactory.VariableDeclarator(SyntaxFactory.Identifier(variable.Name)) + .WithInitializer(equalsValueClause))) + .WithUsingKeyword(usingKeyword); } protected override async Task CreateGeneratedCodeAsync(OperationStatus status, SemanticDocument newDocument, CancellationToken cancellationToken) diff --git a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.cs b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.cs index 10629b4ebe93c..8b6a56a1c0dd8 100644 --- a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.cs +++ b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.cs @@ -140,7 +140,7 @@ protected override async Task CheckTypeAsync( { var typeName = SyntaxFactory.ParseTypeName(typeParameter.Name); var currentType = semanticModel.GetSpeculativeTypeInfo(contextNode.SpanStart, typeName, SpeculativeBindingOption.BindAsTypeOrNamespace).Type; - if (currentType == null || !SymbolEqualityComparer.Default.Equals(currentType, typeParameter)) + if (currentType == null || !SymbolEqualityComparer.Default.Equals(currentType, semanticModel.ResolveType(typeParameter))) { return new OperationStatus(OperationStatusFlag.BestEffort, string.Format(FeaturesResources.Type_parameter_0_is_hidden_by_another_type_parameter_1, diff --git a/src/Features/CSharp/Portable/MakeMethodAsynchronous/CSharpMakeMethodAsynchronousCodeFixProvider.cs b/src/Features/CSharp/Portable/MakeMethodAsynchronous/CSharpMakeMethodAsynchronousCodeFixProvider.cs index f099fee1acd14..cb9ec879b24fe 100644 --- a/src/Features/CSharp/Portable/MakeMethodAsynchronous/CSharpMakeMethodAsynchronousCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/MakeMethodAsynchronous/CSharpMakeMethodAsynchronousCodeFixProvider.cs @@ -106,7 +106,7 @@ private static TypeSyntax FixMethodReturnType( { if (!keepVoid) { - newReturnType = knownTypes._taskType.GenerateTypeSyntax(); + newReturnType = knownTypes.TaskType.GenerateTypeSyntax(); } } else @@ -114,15 +114,15 @@ private static TypeSyntax FixMethodReturnType( var returnType = methodSymbol.ReturnType; if (IsIEnumerable(returnType, knownTypes) && IsIterator(methodSymbol, cancellationToken)) { - newReturnType = knownTypes._iAsyncEnumerableOfTTypeOpt is null + newReturnType = knownTypes.IAsyncEnumerableOfTTypeOpt is null ? MakeGenericType(nameof(IAsyncEnumerable), methodSymbol.ReturnType) - : knownTypes._iAsyncEnumerableOfTTypeOpt.Construct(methodSymbol.ReturnType.GetTypeArguments()[0]).GenerateTypeSyntax(); + : knownTypes.IAsyncEnumerableOfTTypeOpt.Construct(methodSymbol.ReturnType.GetTypeArguments()[0]).GenerateTypeSyntax(); } else if (IsIEnumerator(returnType, knownTypes) && IsIterator(methodSymbol, cancellationToken)) { - newReturnType = knownTypes._iAsyncEnumeratorOfTTypeOpt is null + newReturnType = knownTypes.IAsyncEnumeratorOfTTypeOpt is null ? MakeGenericType(nameof(IAsyncEnumerator), methodSymbol.ReturnType) - : knownTypes._iAsyncEnumeratorOfTTypeOpt.Construct(methodSymbol.ReturnType.GetTypeArguments()[0]).GenerateTypeSyntax(); + : knownTypes.IAsyncEnumeratorOfTTypeOpt.Construct(methodSymbol.ReturnType.GetTypeArguments()[0]).GenerateTypeSyntax(); } else if (IsIAsyncEnumerableOrEnumerator(returnType, knownTypes)) { @@ -132,7 +132,7 @@ private static TypeSyntax FixMethodReturnType( { // If it's not already Task-like, then wrap the existing return type // in Task<>. - newReturnType = knownTypes._taskOfTType.Construct(methodSymbol.ReturnType).GenerateTypeSyntax(); + newReturnType = knownTypes.TaskOfTType.Construct(methodSymbol.ReturnType).GenerateTypeSyntax(); } } @@ -151,14 +151,14 @@ private static bool IsIterator(IMethodSymbol method, CancellationToken cancellat => method.Locations.Any(static (loc, cancellationToken) => loc.FindNode(cancellationToken).ContainsYield(), cancellationToken); private static bool IsIAsyncEnumerableOrEnumerator(ITypeSymbol returnType, KnownTypes knownTypes) - => returnType.OriginalDefinition.Equals(knownTypes._iAsyncEnumerableOfTTypeOpt) || - returnType.OriginalDefinition.Equals(knownTypes._iAsyncEnumeratorOfTTypeOpt); + => returnType.OriginalDefinition.Equals(knownTypes.IAsyncEnumerableOfTTypeOpt) || + returnType.OriginalDefinition.Equals(knownTypes.IAsyncEnumeratorOfTTypeOpt); private static bool IsIEnumerable(ITypeSymbol returnType, KnownTypes knownTypes) - => returnType.OriginalDefinition.Equals(knownTypes._iEnumerableOfTType); + => returnType.OriginalDefinition.Equals(knownTypes.IEnumerableOfTType); private static bool IsIEnumerator(ITypeSymbol returnType, KnownTypes knownTypes) - => returnType.OriginalDefinition.Equals(knownTypes._iEnumeratorOfTType); + => returnType.OriginalDefinition.Equals(knownTypes.IEnumeratorOfTType); private static SyntaxTokenList AddAsyncModifierWithCorrectedTrivia(SyntaxTokenList modifiers, ref TypeSyntax newReturnType) { diff --git a/src/Features/CSharp/Portable/MakeMethodSynchronous/CSharpMakeMethodSynchronousCodeFixProvider.cs b/src/Features/CSharp/Portable/MakeMethodSynchronous/CSharpMakeMethodSynchronousCodeFixProvider.cs index e04ef2518f657..33941cd80d7ae 100644 --- a/src/Features/CSharp/Portable/MakeMethodSynchronous/CSharpMakeMethodSynchronousCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/MakeMethodSynchronous/CSharpMakeMethodSynchronousCodeFixProvider.cs @@ -62,25 +62,25 @@ private static TypeSyntax FixMethodReturnType(IMethodSymbol methodSymbol, TypeSy var newReturnType = returnTypeSyntax; var returnType = methodSymbol.ReturnType; - if (returnType.OriginalDefinition.Equals(knownTypes._taskType)) + if (returnType.OriginalDefinition.Equals(knownTypes.TaskType)) { // If the return type is Task, then make the new return type "void". newReturnType = SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.VoidKeyword)).WithTriviaFrom(returnTypeSyntax); } - else if (returnType.OriginalDefinition.Equals(knownTypes._taskOfTType)) + else if (returnType.OriginalDefinition.Equals(knownTypes.TaskOfTType)) { // If the return type is Task, then make the new return type "T". newReturnType = returnType.GetTypeArguments()[0].GenerateTypeSyntax().WithTriviaFrom(returnTypeSyntax); } - else if (returnType.OriginalDefinition.Equals(knownTypes._iAsyncEnumerableOfTTypeOpt)) + else if (returnType.OriginalDefinition.Equals(knownTypes.IAsyncEnumerableOfTTypeOpt)) { // If the return type is IAsyncEnumerable, then make the new return type IEnumerable. - newReturnType = knownTypes._iEnumerableOfTType.Construct(methodSymbol.ReturnType.GetTypeArguments()[0]).GenerateTypeSyntax(); + newReturnType = knownTypes.IEnumerableOfTType.Construct(methodSymbol.ReturnType.GetTypeArguments()[0]).GenerateTypeSyntax(); } - else if (returnType.OriginalDefinition.Equals(knownTypes._iAsyncEnumeratorOfTTypeOpt)) + else if (returnType.OriginalDefinition.Equals(knownTypes.IAsyncEnumeratorOfTTypeOpt)) { // If the return type is IAsyncEnumerator, then make the new return type IEnumerator. - newReturnType = knownTypes._iEnumeratorOfTType.Construct(methodSymbol.ReturnType.GetTypeArguments()[0]).GenerateTypeSyntax(); + newReturnType = knownTypes.IEnumeratorOfTType.Construct(methodSymbol.ReturnType.GetTypeArguments()[0]).GenerateTypeSyntax(); } return newReturnType; diff --git a/src/Features/CSharp/Portable/Wrapping/CSharpSyntaxWrappingOptions.cs b/src/Features/CSharp/Portable/Wrapping/CSharpSyntaxWrappingOptions.cs index 00c0b4efb6ac3..0cad5e67d3cf9 100644 --- a/src/Features/CSharp/Portable/Wrapping/CSharpSyntaxWrappingOptions.cs +++ b/src/Features/CSharp/Portable/Wrapping/CSharpSyntaxWrappingOptions.cs @@ -6,6 +6,7 @@ using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Formatting; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Wrapping; namespace Microsoft.CodeAnalysis.CSharp.Wrapping @@ -27,11 +28,15 @@ public CSharpSyntaxWrappingOptions( internal static class CSharpSyntaxWrappingOptionsProviders { - public static CSharpSyntaxWrappingOptions GetCSharpSyntaxWrappingOptions(this AnalyzerConfigOptions options, CodeActionOptions fallbackOptions) - => new( + public static CSharpSyntaxWrappingOptions GetCSharpSyntaxWrappingOptions(this IOptionsReader options, CodeActionOptions fallbackOptions) + { + var newLineBeforeOpenBraceDefault = ((CSharpSyntaxFormattingOptions)fallbackOptions.CleanupOptions.FormattingOptions).NewLines.ToNewLineBeforeOpenBracePlacement(); + + return new( options.GetCSharpSyntaxFormattingOptions((CSharpSyntaxFormattingOptions)fallbackOptions.CleanupOptions.FormattingOptions), - operatorPlacement: options.GetOption(CodeStyleOptions2.OperatorPlacementWhenWrapping), + operatorPlacement: options.GetOption(CodeStyleOptions2.OperatorPlacementWhenWrapping, fallbackOptions.CodeStyleOptions.Common.OperatorPlacementWhenWrapping), wrappingColumn: fallbackOptions.WrappingColumn, - newLinesForBracesInObjectCollectionArrayInitializers: options.GetOption(CSharpFormattingOptions2.NewLineBeforeOpenBrace).HasFlag(NewLineBeforeOpenBracePlacement.ObjectCollectionArrayInitializers)); + newLinesForBracesInObjectCollectionArrayInitializers: options.GetOption(CSharpFormattingOptions2.NewLineBeforeOpenBrace, newLineBeforeOpenBraceDefault).HasFlag(NewLineBeforeOpenBracePlacement.ObjectCollectionArrayInitializers)); + } } } diff --git a/src/Features/CSharp/Portable/Wrapping/CSharpWrappingCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/Wrapping/CSharpWrappingCodeRefactoringProvider.cs index 5bcadd7293cb4..32e3e97ebc46a 100644 --- a/src/Features/CSharp/Portable/Wrapping/CSharpWrappingCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/Wrapping/CSharpWrappingCodeRefactoringProvider.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.CSharp.Wrapping.ChainedExpression; using Microsoft.CodeAnalysis.CSharp.Wrapping.SeparatedSyntaxList; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Wrapping; namespace Microsoft.CodeAnalysis.CSharp.Wrapping @@ -33,7 +34,7 @@ public CSharpWrappingCodeRefactoringProvider() { } - protected override SyntaxWrappingOptions GetWrappingOptions(AnalyzerConfigOptions options, CodeActionOptions ideOptions) + protected override SyntaxWrappingOptions GetWrappingOptions(IOptionsReader options, CodeActionOptions ideOptions) => options.GetCSharpSyntaxWrappingOptions(ideOptions); } } diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.cs.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.cs.xlf index 5e9b22bb11723..a6ad57fce8269 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.cs.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.cs.xlf @@ -199,7 +199,7 @@ Enable nullable reference types in solution - Enable nullable reference types in solution + Povolit v řešení typy odkazů s možnou hodnotou null @@ -239,7 +239,7 @@ Selection cannot be in constructor initializer - Selection cannot be in constructor initializer + Výběr nemůže být v inicializátoru konstruktoru. diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf index f1221602a9b48..0a111b4903b01 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf @@ -199,7 +199,7 @@ Enable nullable reference types in solution - Enable nullable reference types in solution + Nullwerte zulassende Verweistypen in der Lösung aktivieren @@ -239,7 +239,7 @@ Selection cannot be in constructor initializer - Selection cannot be in constructor initializer + Die Auswahl kann nicht im Konstruktorinitialisierer enthalten sein diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf index afdcdcebdaf19..4557a09eda8ce 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf @@ -199,7 +199,7 @@ Enable nullable reference types in solution - Enable nullable reference types in solution + Habilitar tipos de referencia que aceptan valores NULL en la solución @@ -239,7 +239,7 @@ Selection cannot be in constructor initializer - Selection cannot be in constructor initializer + La selección no puede estar en el inicializador del constructor diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf index dc6915697c732..9aed46ba38503 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf @@ -199,7 +199,7 @@ Enable nullable reference types in solution - Enable nullable reference types in solution + Activer les types référence Nullable dans la solution @@ -239,7 +239,7 @@ Selection cannot be in constructor initializer - Selection cannot be in constructor initializer + La sélection ne peut pas se trouver dans l’initialiseur du constructeur diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf index 86ed9c4973a3e..71344adf88cb8 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf @@ -199,7 +199,7 @@ Enable nullable reference types in solution - Enable nullable reference types in solution + Abilitare i tipi riferimento nullable nella soluzione @@ -239,7 +239,7 @@ Selection cannot be in constructor initializer - Selection cannot be in constructor initializer + La selezione non può essere nell'inizializzatore del costruttore diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf index 9e2591594f3ca..2e8462fedbed8 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf @@ -199,7 +199,7 @@ Enable nullable reference types in solution - Enable nullable reference types in solution + ソリューションで null 許容参照型を有効にする @@ -239,7 +239,7 @@ Selection cannot be in constructor initializer - Selection cannot be in constructor initializer + 選択範囲をコンストラクター初期化子に含めることはできません diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf index 62f6864244081..9ba2327b49e01 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf @@ -239,7 +239,7 @@ Selection cannot be in constructor initializer - Selection cannot be in constructor initializer + 선택 영역은 생성자 이니셜라이저에 있을 수 없습니다. diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf index 7d2c25c4ec79c..4c880752fced4 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf @@ -239,7 +239,7 @@ Selection cannot be in constructor initializer - Selection cannot be in constructor initializer + Zaznaczenie nie może znajdować się w inicjatorze konstruktora diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf index 8ba478dd0d8fd..ed76b1ba03d4a 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf @@ -199,7 +199,7 @@ Enable nullable reference types in solution - Enable nullable reference types in solution + Habilitar tipos de referência anuláveis na solução @@ -239,7 +239,7 @@ Selection cannot be in constructor initializer - Selection cannot be in constructor initializer + A seleção não pode estar no inicializador do construtor diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf index 5f94c25830da7..4018387aea7ea 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf @@ -199,7 +199,7 @@ Enable nullable reference types in solution - Enable nullable reference types in solution + Включить типы ссылок, допускающие значение NULL, в решение @@ -239,7 +239,7 @@ Selection cannot be in constructor initializer - Selection cannot be in constructor initializer + Выделенный фрагмент не может быть в инициализаторе конструктора diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf index faed53d6c918a..2280b4a44d90d 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf @@ -199,7 +199,7 @@ Enable nullable reference types in solution - Enable nullable reference types in solution + Çözümdeki null atanabilir başvuru türlerini etkinleştir @@ -239,7 +239,7 @@ Selection cannot be in constructor initializer - Selection cannot be in constructor initializer + Seçim, oluşturucu başlatıcıda olamaz diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf index 04abe9206115b..c4666685a7c52 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf @@ -199,7 +199,7 @@ Enable nullable reference types in solution - Enable nullable reference types in solution + 在解决方案中启用可为 null 的引用类型 @@ -239,7 +239,7 @@ Selection cannot be in constructor initializer - Selection cannot be in constructor initializer + 选择不能位于构造函数初始化表达式中 @@ -779,7 +779,7 @@ ... without leading whitespace (may change semantics) - ...不带前导空格(可能会更改语义) + ...不带前导空格 (可能会更改语义) This clause is a follow up to the "Convert to raw string" loc string. The intent is that the user sees "Convert to raw string" as an option to select, and that is then followed with this clause. This is so we don't have a huge string diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf index bfb0ca5e6f40b..38312939a98be 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf @@ -199,7 +199,7 @@ Enable nullable reference types in solution - Enable nullable reference types in solution + 在解決方案中啟用可 null 的參考類型 @@ -239,7 +239,7 @@ Selection cannot be in constructor initializer - Selection cannot be in constructor initializer + 選取範圍不能是使用建構函式初始設定式 diff --git a/src/Features/Core/Portable/ClassifiedSpansAndHighlightSpanFactory.cs b/src/Features/Core/Portable/ClassifiedSpansAndHighlightSpanFactory.cs index 2c7145b230032..7add0212992d1 100644 --- a/src/Features/Core/Portable/ClassifiedSpansAndHighlightSpanFactory.cs +++ b/src/Features/Core/Portable/ClassifiedSpansAndHighlightSpanFactory.cs @@ -4,6 +4,7 @@ #nullable disable +using System; using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; @@ -60,7 +61,11 @@ private static TextSpan GetLineSpanForReference(SourceText sourceText, TextSpan var sourceLine = sourceText.Lines.GetLineFromPosition(referenceSpan.Start); var firstNonWhitespacePosition = sourceLine.GetFirstNonWhitespacePosition().Value; - return TextSpan.FromBounds(firstNonWhitespacePosition, sourceLine.End); + // Get the span of the line from the first non-whitespace character to the end of it. Note: the reference + // span might actually start in the leading whitespace of the line (nothing prevents any of our + // languages/providers from doing that), so ensure that the line snap we clip out at least starts at that + // position so that our span math will be correct. + return TextSpan.FromBounds(Math.Min(firstNonWhitespacePosition, referenceSpan.Start), sourceLine.End); } private static async Task GetTaggedTextForDocumentRegionAsync( diff --git a/src/Features/Core/Portable/CodeFixes/AbstractConfigurationActionWithNestedActions.cs b/src/Features/Core/Portable/CodeFixes/AbstractConfigurationActionWithNestedActions.cs index b30a81e31f055..e001a5f1212c5 100644 --- a/src/Features/Core/Portable/CodeFixes/AbstractConfigurationActionWithNestedActions.cs +++ b/src/Features/Core/Portable/CodeFixes/AbstractConfigurationActionWithNestedActions.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using Microsoft.CodeAnalysis.CodeActions; diff --git a/src/Features/Core/Portable/CodeFixes/Configuration/ConfigurationUpdater.cs b/src/Features/Core/Portable/CodeFixes/Configuration/ConfigurationUpdater.cs index 7ad4935eac530..9052f95c46190 100644 --- a/src/Features/Core/Portable/CodeFixes/Configuration/ConfigurationUpdater.cs +++ b/src/Features/Core/Portable/CodeFixes/Configuration/ConfigurationUpdater.cs @@ -363,15 +363,10 @@ private async Task ConfigureAsync() try { - foreach (var (optionKey, editorConfigLocation) in codeStyleOptions) + foreach (var option in codeStyleOptions) { - if (!TryGetEditorConfigStringParts(editorConfigLocation.GetEditorConfigString(optionKey.Option.DefaultValue), out var parts)) - { - // Did not find a match, bail out. - return ImmutableArray<(string optionName, string currentOptionValue, bool isPerLanguage)>.Empty; - } - - builder.Add((parts.optionName, parts.optionValue, optionKey.Option.IsPerLanguage)); + var optionValue = option.Definition.Serializer.Serialize(option.DefaultValue); + builder.Add((option.Definition.ConfigName, optionValue, option.IsPerLanguage)); } return builder.ToImmutable(); @@ -402,32 +397,17 @@ internal static bool TryGetEditorConfigStringParts(string editorConfigString, ou return false; } - internal static ImmutableArray<(OptionKey optionKey, IEditorConfigStorageLocation2 location)> GetCodeStyleOptionsForDiagnostic( - Diagnostic diagnostic, - Project project) + internal static ImmutableArray GetCodeStyleOptionsForDiagnostic(Diagnostic diagnostic, Project project) { if (IDEDiagnosticIdToOptionMappingHelper.TryGetMappedOptions(diagnostic.Id, project.Language, out var options)) { - using var _ = ArrayBuilder<(OptionKey, IEditorConfigStorageLocation2)>.GetInstance(out var builder); - - foreach (var option in options.OrderBy(option => option.Name)) - { - var editorConfigLocation = option.StorageLocations.OfType().FirstOrDefault(); - if (editorConfigLocation != null && option.DefaultValue is ICodeStyleOption codeStyleOption) - { - var optionKey = new OptionKey(option, option.IsPerLanguage ? project.Language : null); - builder.Add((optionKey, editorConfigLocation)); - continue; - } - - // Did not find a match. - return ImmutableArray<(OptionKey, IEditorConfigStorageLocation2)>.Empty; - } - - return builder.ToImmutable(); + return (from option in options + where option.DefaultValue is ICodeStyleOption + orderby option.Definition.ConfigName + select option).ToImmutableArray(); } - return ImmutableArray<(OptionKey, IEditorConfigStorageLocation2)>.Empty; + return ImmutableArray.Empty; } private SourceText? GetNewAnalyzerConfigDocumentText(SourceText originalText, AnalyzerConfigDocument editorConfigDocument) diff --git a/src/Features/Core/Portable/CodeFixes/Configuration/ConfigureCodeStyle/ConfigureCodeStyleOptionCodeFixProvider.TopLevelConfigureCodeStyleOptionCodeAction.cs b/src/Features/Core/Portable/CodeFixes/Configuration/ConfigureCodeStyle/ConfigureCodeStyleOptionCodeFixProvider.TopLevelConfigureCodeStyleOptionCodeAction.cs index 02677b45acf17..2d5cf20da4ce3 100644 --- a/src/Features/Core/Portable/CodeFixes/Configuration/ConfigureCodeStyle/ConfigureCodeStyleOptionCodeFixProvider.TopLevelConfigureCodeStyleOptionCodeAction.cs +++ b/src/Features/Core/Portable/CodeFixes/Configuration/ConfigureCodeStyle/ConfigureCodeStyleOptionCodeFixProvider.TopLevelConfigureCodeStyleOptionCodeAction.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using Microsoft.CodeAnalysis.CodeActions; diff --git a/src/Features/Core/Portable/CodeFixes/Configuration/ConfigureCodeStyle/ConfigureCodeStyleOptionCodeFixProvider.cs b/src/Features/Core/Portable/CodeFixes/Configuration/ConfigureCodeStyle/ConfigureCodeStyleOptionCodeFixProvider.cs index 5178e9bad94bb..9224b8e1dab6e 100644 --- a/src/Features/Core/Portable/CodeFixes/Configuration/ConfigureCodeStyle/ConfigureCodeStyleOptionCodeFixProvider.cs +++ b/src/Features/Core/Portable/CodeFixes/Configuration/ConfigureCodeStyle/ConfigureCodeStyleOptionCodeFixProvider.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using System.Collections.Immutable; @@ -20,6 +18,7 @@ using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; using static Microsoft.CodeAnalysis.CodeActions.CodeAction; namespace Microsoft.CodeAnalysis.CodeFixes.Configuration.ConfigureCodeStyle @@ -49,12 +48,10 @@ public bool IsFixableDiagnostic(Diagnostic diagnostic) } var language = diagnostic.Location.SourceTree.Options.Language; - return IDEDiagnosticIdToOptionMappingHelper.TryGetMappedOptions(diagnostic.Id, language, out var options) && - !options.IsEmpty && - options.All(o => o.StorageLocations.Any(static l => l is IEditorConfigStorageLocation2)); + return IDEDiagnosticIdToOptionMappingHelper.TryGetMappedOptions(diagnostic.Id, language, out _); } - public FixAllProvider GetFixAllProvider() + public FixAllProvider? GetFixAllProvider() => null; public Task> GetFixesAsync(TextDocument document, TextSpan span, IEnumerable diagnostics, CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) @@ -80,9 +77,9 @@ private static ImmutableArray GetConfigurations(Project project, IEnume // for 'false' setting. If the option value is CodeStyleOption, we will have a nested action for each enum field. using var _ = ArrayBuilder.GetInstance(out var nestedActions); var hasMultipleOptions = codeStyleOptions.Length > 1; - foreach (var (optionKey, editorConfigLocation) in codeStyleOptions.OrderBy(t => t.optionKey.Option.Name)) + foreach (var option in codeStyleOptions) { - var topLevelAction = GetCodeActionForCodeStyleOption(optionKey, editorConfigLocation, diagnostic, hasMultipleOptions); + var topLevelAction = GetCodeActionForCodeStyleOption(option, diagnostic, hasMultipleOptions); if (topLevelAction != null) { nestedActions.Add(topLevelAction); @@ -103,19 +100,18 @@ private static ImmutableArray GetConfigurations(Project project, IEnume return result.ToImmutableAndFree(); // Local functions - TopLevelConfigureCodeStyleOptionCodeAction GetCodeActionForCodeStyleOption( - OptionKey optionKey, - IEditorConfigStorageLocation2 editorConfigLocation, - Diagnostic diagnostic, - bool hasMultipleOptions) + TopLevelConfigureCodeStyleOptionCodeAction? GetCodeActionForCodeStyleOption(IOption2 option, Diagnostic diagnostic, bool hasMultipleOptions) { // Add a code action for every valid value of the given code style option. // We only support light-bulb configuration of code style options with boolean or enum values. using var _ = ArrayBuilder.GetInstance(out var nestedActions); - string optionName = null; - var defaultValue = (ICodeStyleOption)optionKey.Option.DefaultValue; + // Try to get the parsed editorconfig string representation of the new code style option value + var optionName = option.Definition.ConfigName; + var defaultValue = (ICodeStyleOption?)option.DefaultValue; + Contract.ThrowIfNull(defaultValue); + if (defaultValue.Value is bool) { foreach (var boolValue in s_boolValues) @@ -127,7 +123,7 @@ TopLevelConfigureCodeStyleOptionCodeAction GetCodeActionForCodeStyleOption( { foreach (var enumValue in Enum.GetValues(t)) { - AddCodeActionWithOptionValue(defaultValue, enumValue); + AddCodeActionWithOptionValue(defaultValue, enumValue!); } } @@ -148,21 +144,14 @@ void AddCodeActionWithOptionValue(ICodeStyleOption codeStyleOption, object newVa { // Create a new code style option value with the newValue var configuredCodeStyleOption = codeStyleOption.WithValue(newValue); - - // Try to get the parsed editorconfig string representation of the new code style option value - if (ConfigurationUpdater.TryGetEditorConfigStringParts(editorConfigLocation.GetEditorConfigString(configuredCodeStyleOption), out var parts)) - { - // We expect all code style values for same code style option to have the same editorconfig option name. - Debug.Assert(optionName == null || optionName == parts.optionName); - optionName ??= parts.optionName; - - // Add code action to configure the optionValue. - nestedActions.Add( - SolutionChangeAction.Create( - parts.optionValue, - solution => ConfigurationUpdater.ConfigureCodeStyleOptionAsync(parts.optionName, parts.optionValue, diagnostic, optionKey.Option.IsPerLanguage, project, cancellationToken), - parts.optionValue)); - } + var optionValue = option.Definition.Serializer.Serialize(configuredCodeStyleOption); + + // Add code action to configure the optionValue. + nestedActions.Add( + SolutionChangeAction.Create( + optionValue, + solution => ConfigurationUpdater.ConfigureCodeStyleOptionAsync(optionName, optionValue, diagnostic, option.IsPerLanguage, project, cancellationToken), + optionValue)); } } } diff --git a/src/Features/Core/Portable/Completion/CompletionContext.cs b/src/Features/Core/Portable/Completion/CompletionContext.cs index bbd707306e25b..cc579d4ec7fc9 100644 --- a/src/Features/Core/Portable/Completion/CompletionContext.cs +++ b/src/Features/Core/Portable/Completion/CompletionContext.cs @@ -129,7 +129,7 @@ public CompletionContext( cancellationToken) { #pragma warning disable RS0030 // Do not used banned APIs - Options = options ?? OptionValueSet.Empty; + Options = options ?? OptionSet.Empty; #pragma warning restore } @@ -157,7 +157,7 @@ internal CompletionContext( SharedSyntaxContextsWithSpeculativeModel = sharedSyntaxContextsWithSpeculativeModel; #pragma warning disable RS0030 // Do not used banned APIs - Options = OptionValueSet.Empty; + Options = OptionSet.Empty; #pragma warning restore } diff --git a/src/Features/Core/Portable/Completion/CompletionOptions.cs b/src/Features/Core/Portable/Completion/CompletionOptions.cs index 1f6ae658f7e85..a251bd2866530 100644 --- a/src/Features/Core/Portable/Completion/CompletionOptions.cs +++ b/src/Features/Core/Portable/Completion/CompletionOptions.cs @@ -24,8 +24,18 @@ internal sealed record class CompletionOptions public bool TargetTypedCompletionFilter { get; init; } = false; public bool ProvideDateAndTimeCompletions { get; init; } = true; public bool ProvideRegexCompletions { get; init; } = true; + + /// + /// Test-only option. + /// public bool ForceExpandedCompletionIndexCreation { get; init; } = false; + + /// + /// Set to true to update import completion cache in background if the provider isn't supposed to be triggered in the context. + /// (cache will always be refreshed when provider is triggered) + /// public bool UpdateImportCompletionCacheInBackground { get; init; } = false; + public bool FilterOutOfScopeLocals { get; init; } = true; public bool ShowXmlDocCommentCompletion { get; init; } = true; public bool? ShowNewSnippetExperienceUserOption { get; init; } = null; diff --git a/src/Features/Core/Portable/Completion/CompletionService.cs b/src/Features/Core/Portable/Completion/CompletionService.cs index 221d80d26e1ce..17b74df48ecde 100644 --- a/src/Features/Core/Portable/Completion/CompletionService.cs +++ b/src/Features/Core/Portable/Completion/CompletionService.cs @@ -103,7 +103,7 @@ public bool ShouldTriggerCompletion( // Publicly available options do not affect this API. var completionOptions = CompletionOptions.Default; - var passThroughOptions = options ?? document?.Project.Solution.Options ?? OptionValueSet.Empty; + var passThroughOptions = options ?? document?.Project.Solution.Options ?? OptionSet.Empty; return ShouldTriggerCompletion(document?.Project, languageServices, text, caretPosition, trigger, completionOptions, passThroughOptions, roles); } diff --git a/src/Features/Core/Portable/ConvertLinq/ConvertForEachToLinqQuery/AbstractConvertForEachToLinqQueryProvider.cs b/src/Features/Core/Portable/ConvertLinq/ConvertForEachToLinqQuery/AbstractConvertForEachToLinqQueryProvider.cs index 8719ee2a6bca3..f3ffe0198f334 100644 --- a/src/Features/Core/Portable/ConvertLinq/ConvertForEachToLinqQuery/AbstractConvertForEachToLinqQueryProvider.cs +++ b/src/Features/Core/Portable/ConvertLinq/ConvertForEachToLinqQuery/AbstractConvertForEachToLinqQueryProvider.cs @@ -2,7 +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.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; @@ -39,7 +38,7 @@ protected abstract bool TryBuildSpecificConverter( SemanticModel semanticModel, TStatement statementCannotBeConverted, CancellationToken cancellationToken, - out IConverter converter); + [NotNullWhen(true)] out IConverter? converter); /// /// Creates a default converter where foreach is joined with some children statements but other children statements are kept unmodified. @@ -66,7 +65,6 @@ protected abstract SyntaxNode AddLinqUsing( public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var (document, _, cancellationToken) = context; - var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var forEachStatement = await context.TryGetRelevantNodeAsync().ConfigureAwait(false); if (forEachStatement == null) diff --git a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs index 3e5c206d32d24..83dd5f45705d8 100644 --- a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs +++ b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs @@ -74,6 +74,9 @@ protected AbstractEditAndContinueAnalyzer(Action? testFaultInjector) _testFaultInjector = testFaultInjector; } + private static TraceLog Log + => EditAndContinueWorkspaceService.AnalysisLog; + internal abstract bool ExperimentalFeaturesEnabled(SyntaxTree tree); /// @@ -512,8 +515,6 @@ public async Task AnalyzeDocumentAsync( Debug.Assert(newDocument.SupportsSemanticModel); Debug.Assert(filePath != null); - DocumentAnalysisResults.Log.Write("Analyzing document '{0}'", filePath); - // assume changes until we determine there are none so that EnC is blocked on unexpected exception: var hasChanges = true; @@ -560,7 +561,7 @@ public async Task AnalyzeDocumentAsync( { // Bail, since we can't do syntax diffing on broken trees (it would not produce useful results anyways). // If we needed to do so for some reason, we'd need to harden the syntax tree comparers. - DocumentAnalysisResults.Log.Write("{0}: syntax errors", filePath); + Log.Write("Syntax errors found in '{0}'", filePath); return DocumentAnalysisResults.SyntaxErrors(newDocument.Id, filePath, ImmutableArray.Empty, syntaxError, hasChanges); } @@ -571,7 +572,7 @@ public async Task AnalyzeDocumentAsync( // a) comparing texts is cheaper than diffing trees // b) we need to ignore errors in unchanged documents - DocumentAnalysisResults.Log.Write("{0}: unchanged", filePath); + Log.Write("Document unchanged: '{0}'", filePath); return DocumentAnalysisResults.Unchanged(newDocument.Id, filePath); } @@ -579,7 +580,7 @@ public async Task AnalyzeDocumentAsync( // These features may not be handled well by the analysis below. if (ExperimentalFeaturesEnabled(newTree)) { - DocumentAnalysisResults.Log.Write("{0}: experimental features enabled", filePath); + Log.Write("Experimental features enabled in '{0}'", filePath); return DocumentAnalysisResults.SyntaxErrors(newDocument.Id, filePath, ImmutableArray.Create( new RudeEditDiagnostic(RudeEditKind.ExperimentalFeaturesEnabled, default)), syntaxError: null, hasChanges); @@ -611,16 +612,9 @@ public async Task AnalyzeDocumentAsync( var topMatch = ComputeTopLevelMatch(oldRoot, newRoot); var syntacticEdits = topMatch.GetTreeEdits(); var editMap = BuildEditMap(syntacticEdits); - var hasRudeEdits = false; ReportTopLevelSyntacticRudeEdits(diagnostics, syntacticEdits, editMap); - if (diagnostics.Count > 0 && !hasRudeEdits) - { - DocumentAnalysisResults.Log.Write("{0} syntactic rude edits, first: '{1}'", diagnostics.Count, filePath); - hasRudeEdits = true; - } - cancellationToken.ThrowIfCancellationRequested(); using var _3 = ArrayBuilder<(SyntaxNode OldNode, SyntaxNode NewNode, TextSpan DiagnosticSpan)>.GetInstance(out var triviaEdits); @@ -666,10 +660,14 @@ public async Task AnalyzeDocumentAsync( AnalyzeUnchangedActiveMemberBodies(diagnostics, syntacticEdits.Match, newText, oldActiveStatements, newActiveStatementSpans, newActiveStatements, newExceptionRegions, cancellationToken); Debug.Assert(newActiveStatements.All(a => a != null)); - if (diagnostics.Count > 0 && !hasRudeEdits) + var hasRudeEdits = diagnostics.Count > 0; + if (hasRudeEdits) { - DocumentAnalysisResults.Log.Write("{0}@{1}: rude edit ({2} total)", filePath, diagnostics.First().Span.Start, diagnostics.Count); - hasRudeEdits = true; + LogRudeEdits(diagnostics, newText, filePath); + } + else + { + Log.Write("Capabilities required by '{0}': {1}", filePath, capabilities.GrantedCapabilities); } return new DocumentAnalysisResults( @@ -698,6 +696,28 @@ public async Task AnalyzeDocumentAsync( // Report as "syntax error" - we can't analyze the document return DocumentAnalysisResults.SyntaxErrors(newDocument.Id, filePath, ImmutableArray.Create(diagnostic), syntaxError: null, hasChanges); } + + static void LogRudeEdits(ArrayBuilder diagnostics, SourceText text, string filePath) + { + foreach (var diagnostic in diagnostics) + { + int lineNumber; + string? lineText; + try + { + var line = text.Lines.GetLineFromPosition(diagnostic.Span.Start); + lineNumber = line.LineNumber; + lineText = text.ToString(TextSpan.FromBounds(diagnostic.Span.Start, Math.Min(diagnostic.Span.Start + 120, line.End))); + } + catch + { + lineNumber = -1; + lineText = null; + } + + Log.Write("Rude edit {0}:{1} '{2}' line {3}: '{4}'", diagnostic.Kind, diagnostic.SyntaxKind, filePath, lineNumber, lineText); + } + } } private void ReportTopLevelSyntacticRudeEdits(ArrayBuilder diagnostics, EditScript syntacticEdits, Dictionary editMap) @@ -810,7 +830,7 @@ private void AnalyzeUnchangedActiveMemberBodies( // Guard against invalid active statement spans (in case PDB was somehow out of sync with the source). if (oldBody == null || newBody == null) { - DocumentAnalysisResults.Log.Write("Invalid active statement span: [{0}..{1})", oldStatementSpan.Start, oldStatementSpan.End); + Log.Write("Invalid active statement span: [{0}..{1})", oldStatementSpan.Start, oldStatementSpan.End); continue; } @@ -860,7 +880,7 @@ private void AnalyzeUnchangedActiveMemberBodies( } else { - DocumentAnalysisResults.Log.Write("Invalid active statement span: [{0}..{1})", oldStatementSpan.Start, oldStatementSpan.End); + Log.Write("Invalid active statement span: [{0}..{1})", oldStatementSpan.Start, oldStatementSpan.End); } // we were not able to determine the active statement location (PDB data might be invalid) diff --git a/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs b/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs index 4e03d5f8979e9..61cd18beadb3c 100644 --- a/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs +++ b/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs @@ -71,6 +71,11 @@ internal sealed class DebuggingSession : IDisposable internal readonly DebuggingSessionId Id; + /// + /// Incremented on every emit update invocation. Used by logging. + /// + private int _updateOrdinal; + /// /// The solution captured when the debugging session entered run mode (application debugging started), /// or the solution which the last changes committed to the debuggee at the end of edit session were calculated from. @@ -522,9 +527,11 @@ public async ValueTask EmitSolutionUpdateAsync( { ThrowIfDisposed(); - var solutionUpdate = await EditSession.EmitSolutionUpdateAsync(solution, activeStatementSpanProvider, cancellationToken).ConfigureAwait(false); + var updateId = new UpdateId(Id, Interlocked.Increment(ref _updateOrdinal)); + + var solutionUpdate = await EditSession.EmitSolutionUpdateAsync(solution, activeStatementSpanProvider, updateId, cancellationToken).ConfigureAwait(false); - LogSolutionUpdate(solutionUpdate); + LogSolutionUpdate(solutionUpdate, updateId); if (solutionUpdate.ModuleUpdates.Status == ModuleUpdateStatus.Ready) { @@ -536,11 +543,11 @@ public async ValueTask EmitSolutionUpdateAsync( return new EmitSolutionUpdateResults(solutionUpdate.ModuleUpdates, solutionUpdate.Diagnostics, solutionUpdate.DocumentsWithRudeEdits, solutionUpdate.SyntaxError); } - private void LogSolutionUpdate(SolutionUpdate update) + private void LogSolutionUpdate(SolutionUpdate update, UpdateId updateId) { var log = EditAndContinueWorkspaceService.Log; - log.Write("Solution update status: {0}", update.ModuleUpdates.Status); + log.Write("Solution update {0}.{1} status: {2}", updateId.SessionId.Ordinal, updateId.Ordinal, update.ModuleUpdates.Status); foreach (var moduleUpdate in update.ModuleUpdates.Updates) { diff --git a/src/Features/Core/Portable/EditAndContinue/DebuggingSessionId.cs b/src/Features/Core/Portable/EditAndContinue/DebuggingSessionId.cs index 41e0946b46176..50a5eca2ef628 100644 --- a/src/Features/Core/Portable/EditAndContinue/DebuggingSessionId.cs +++ b/src/Features/Core/Portable/EditAndContinue/DebuggingSessionId.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. -using System; using System.Runtime.Serialization; -using System.Threading; namespace Microsoft.CodeAnalysis.EditAndContinue; @@ -14,3 +12,5 @@ internal readonly record struct DebuggingSessionId([property: DataMember] int Or public override string ToString() => Ordinal.ToString(); } + +internal readonly record struct UpdateId(DebuggingSessionId SessionId, int Ordinal); diff --git a/src/Features/Core/Portable/EditAndContinue/DocumentAnalysisResults.cs b/src/Features/Core/Portable/EditAndContinue/DocumentAnalysisResults.cs index fc5154393700c..272fb41b9b58a 100644 --- a/src/Features/Core/Portable/EditAndContinue/DocumentAnalysisResults.cs +++ b/src/Features/Core/Portable/EditAndContinue/DocumentAnalysisResults.cs @@ -13,8 +13,6 @@ namespace Microsoft.CodeAnalysis.EditAndContinue { internal sealed class DocumentAnalysisResults { - internal static readonly TraceLog Log = new(256, "EnC", logDirectory: null); - /// /// The state of the document the results are calculated for. /// diff --git a/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs b/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs index 41d8db88e7e29..762506a8a9485 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs @@ -26,7 +26,8 @@ namespace Microsoft.CodeAnalysis.EditAndContinue [ExportWorkspaceService(typeof(IEditAndContinueWorkspaceService)), Shared] internal sealed class EditAndContinueWorkspaceService : IEditAndContinueWorkspaceService { - internal static readonly TraceLog Log = new(2048, "EnC", GetLogDirectory()); + internal static readonly TraceLog Log; + internal static readonly TraceLog AnalysisLog; private Func _compilationOutputsProvider; @@ -43,6 +44,13 @@ public EditAndContinueWorkspaceService() _compilationOutputsProvider = GetCompilationOutputs; } + static EditAndContinueWorkspaceService() + { + var logDir = GetLogDirectory(); + Log = new(2048, "EnC", "Trace.log", logDir); + AnalysisLog = new(1024, "EnC", "Analysis.log", logDir); + } + private static string? GetLogDirectory() { try diff --git a/src/Features/Core/Portable/EditAndContinue/EditSession.cs b/src/Features/Core/Portable/EditAndContinue/EditSession.cs index e04d9cdf7e119..845294c7312a9 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditSession.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditSession.cs @@ -792,13 +792,13 @@ internal static void MergePartialEdits( addedSymbols = addedSymbolsBuilder.ToImmutableHashSet(); } - public async ValueTask EmitSolutionUpdateAsync(Solution solution, ActiveStatementSpanProvider solutionActiveStatementSpanProvider, CancellationToken cancellationToken) + public async ValueTask EmitSolutionUpdateAsync(Solution solution, ActiveStatementSpanProvider solutionActiveStatementSpanProvider, UpdateId updateId, CancellationToken cancellationToken) { try { var log = EditAndContinueWorkspaceService.Log; - log.Write("EmitSolutionUpdate: '{0}'", solution.FilePath); + log.Write("EmitSolutionUpdate {0}.{1}: '{2}'", updateId.SessionId.Ordinal, updateId.Ordinal, solution.FilePath); using var _1 = ArrayBuilder.GetInstance(out var deltas); using var _2 = ArrayBuilder<(Guid ModuleId, ImmutableArray<(ManagedModuleMethodId Method, NonRemappableRegion Region)>)>.GetInstance(out var nonRemappableRegions); @@ -935,6 +935,8 @@ public async ValueTask EmitSolutionUpdateAsync(Solution solution if (isModuleEncBlocked || projectSummary != ProjectAnalysisSummary.ValidChanges) { Telemetry.LogProjectAnalysisSummary(projectSummary, newProject.State.ProjectInfo.Attributes.TelemetryId, moduleDiagnostics.NullToEmpty().SelectAsArray(d => d.Descriptor.Id)); + + await LogDocumentChangesAsync(generation: null, cancellationToken).ConfigureAwait(false); continue; } @@ -947,24 +949,31 @@ public async ValueTask EmitSolutionUpdateAsync(Solution solution diagnostics.Add((newProject.Id, createBaselineDiagnostics)); Telemetry.LogProjectAnalysisSummary(projectSummary, newProject.State.ProjectInfo.Attributes.TelemetryId, createBaselineDiagnostics); isBlocked = true; + + await LogDocumentChangesAsync(generation: null, cancellationToken).ConfigureAwait(false); continue; } - log.Write("Emitting update of '{0}'", newProject.Id); + await LogDocumentChangesAsync(baselineGeneration + 1, cancellationToken).ConfigureAwait(false); - if (log.FileLoggingEnabled) + async ValueTask LogDocumentChangesAsync(int? generation, CancellationToken cancellationToken) { - foreach (var changedDocumentAnalysis in changedDocumentAnalyses) + if (log.FileLoggingEnabled) { - if (changedDocumentAnalysis.HasChanges) + foreach (var changedDocumentAnalysis in changedDocumentAnalyses) { - var oldDocument = await oldProject.GetDocumentAsync(changedDocumentAnalysis.DocumentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false); - var newDocument = await newProject.GetDocumentAsync(changedDocumentAnalysis.DocumentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false); - await log.WriteDocumentChangeAsync(oldDocument, newDocument, DebuggingSession.Id, baselineGeneration + 1, cancellationToken).ConfigureAwait(false); + if (changedDocumentAnalysis.HasChanges) + { + var oldDocument = await oldProject.GetDocumentAsync(changedDocumentAnalysis.DocumentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false); + var newDocument = await newProject.GetDocumentAsync(changedDocumentAnalysis.DocumentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false); + await log.WriteDocumentChangeAsync(oldDocument, newDocument, updateId, generation, cancellationToken).ConfigureAwait(false); + } } } } + log.Write("Emitting update of '{0}'", newProject.Id); + var oldCompilation = await oldProject.GetCompilationAsync(cancellationToken).ConfigureAwait(false); var newCompilation = await newProject.GetCompilationAsync(cancellationToken).ConfigureAwait(false); Contract.ThrowIfNull(oldCompilation); diff --git a/src/Features/Core/Portable/EditAndContinue/TraceLog.cs b/src/Features/Core/Portable/EditAndContinue/TraceLog.cs index bba40191cb4cc..b68c49cfef2e0 100644 --- a/src/Features/Core/Portable/EditAndContinue/TraceLog.cs +++ b/src/Features/Core/Portable/EditAndContinue/TraceLog.cs @@ -114,13 +114,15 @@ internal string GetDebuggerDisplay() private readonly Entry[] _log; private readonly string _id; + private readonly string _fileName; private readonly string? _logDirectory; private int _currentLine; - public TraceLog(int logSize, string id, string? logDirectory) + public TraceLog(int logSize, string id, string fileName, string? logDirectory) { _log = new Entry[logSize]; _id = id; + _fileName = fileName; _logDirectory = logDirectory; } @@ -143,7 +145,7 @@ private void AppendToFile(Entry entry) try { - path = Path.Combine(_logDirectory, "Trace.log"); + path = Path.Combine(_logDirectory, _fileName); File.AppendAllLines(path, new[] { entry.GetDebuggerDisplay() }); } catch (Exception e) @@ -188,7 +190,7 @@ private string CreateSessionDirectory(DebuggingSessionId sessionId, string relat return directory; } - private string MakeSourceFileLogPath(Document document, string suffix, DebuggingSessionId sessionId, int generation) + private string MakeSourceFileLogPath(Document document, string suffix, UpdateId updateId, int? generation) { Debug.Assert(document.FilePath != null); Debug.Assert(document.Project.FilePath != null); @@ -201,8 +203,8 @@ private string MakeSourceFileLogPath(Document document, string suffix, Debugging var relativeDir = PathUtilities.IsSameDirectoryOrChildOf(documentDir, projectDir) ? PathUtilities.GetRelativePath(projectDir, documentDir) : documentDir; relativeDir = relativeDir.Replace('\\', '_').Replace('/', '_'); - var directory = CreateSessionDirectory(sessionId, Path.Combine(document.Project.Name, relativeDir)); - return Path.Combine(directory, $"{fileName}.{generation}.{suffix}{extension}"); + var directory = CreateSessionDirectory(updateId.SessionId, Path.Combine(document.Project.Name, relativeDir)); + return Path.Combine(directory, $"{fileName}.{updateId.Ordinal}.{generation?.ToString() ?? "-"}.{suffix}{extension}"); } public void WriteToFile(DebuggingSessionId sessionId, ImmutableArray bytes, string directory, string fileName) @@ -234,14 +236,14 @@ public async ValueTask WriteToFileAsync(Func _currentToken.Kind switch + { + try { - JsonKind.OpenBraceToken => ParseObject(), - JsonKind.OpenBracketToken => ParseArray(), - JsonKind.CommaToken => ParseCommaValue(), - _ => ParseLiteralOrPropertyOrConstructor(), - }; + _recursionDepth++; + StackGuard.EnsureSufficientExecutionStack(_recursionDepth); + + return _currentToken.Kind switch + { + JsonKind.OpenBraceToken => ParseObject(), + JsonKind.OpenBracketToken => ParseArray(), + JsonKind.CommaToken => ParseCommaValue(), + _ => ParseLiteralOrPropertyOrConstructor(), + }; + } + finally + { + _recursionDepth--; + } + } private static void SplitLiteral(JsonToken literalToken, out JsonToken minusToken, out JsonToken newLiteralToken) { diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingSolutionCrawlerService.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingSolutionCrawlerService.cs index e2219c703b78c..80c850d6fe348 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingSolutionCrawlerService.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingSolutionCrawlerService.cs @@ -13,8 +13,7 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.SolutionCrawler { internal partial class UnitTestingSolutionCrawlerRegistrationService : IUnitTestingSolutionCrawlerRegistrationService { - internal static readonly Option2 EnableSolutionCrawler = new("InternalSolutionCrawlerOptions", "Solution Crawler", defaultValue: true, - storageLocation: new LocalUserProfileStorageLocation(@"Roslyn\Internal\SolutionCrawler\Solution Crawler")); + internal static readonly Option2 EnableSolutionCrawler = new("InternalSolutionCrawlerOptions_Solution Crawler", defaultValue: true); /// /// nested class of since it is tightly coupled with it. diff --git a/src/Features/Core/Portable/ExtractClass/AbstractExtractClassRefactoringProvider.cs b/src/Features/Core/Portable/ExtractClass/AbstractExtractClassRefactoringProvider.cs index 3056207ce7901..cb38ecce33550 100644 --- a/src/Features/Core/Portable/ExtractClass/AbstractExtractClassRefactoringProvider.cs +++ b/src/Features/Core/Portable/ExtractClass/AbstractExtractClassRefactoringProvider.cs @@ -46,10 +46,14 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte return; } - // If we register the action on a class node, no need to find selected members. Just allow - // the action to be invoked with the dialog and no selected members - var action = await TryGetClassActionAsync(context, optionsService).ConfigureAwait(false) - ?? await TryGetMemberActionAsync(context, optionsService).ConfigureAwait(false); + var (action, hasBaseType) = await TryGetMemberActionAsync(context, optionsService).ConfigureAwait(false); + + // If the action was not offered because we know the containing type + // already has a base class, no need to do extra work to see if just a class is selected + if (action is null && !hasBaseType) + { + action = await TryGetClassActionAsync(context, optionsService).ConfigureAwait(false); + } if (action != null) { @@ -57,12 +61,12 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte } } - private async Task TryGetMemberActionAsync(CodeRefactoringContext context, IExtractClassOptionsService optionsService) + private async Task<(ExtractClassWithDialogCodeAction? action, bool hasBaseType)> TryGetMemberActionAsync(CodeRefactoringContext context, IExtractClassOptionsService optionsService) { var selectedMemberNodes = await GetSelectedNodesAsync(context).ConfigureAwait(false); if (selectedMemberNodes.IsEmpty) { - return null; + return (null, false); } var (document, span, cancellationToken) = context; @@ -75,7 +79,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte if (memberNodeSymbolPairs.IsEmpty) { - return null; + return (null, false); } var selectedMembers = memberNodeSymbolPairs.SelectAsArray(pair => pair.symbol); @@ -90,12 +94,9 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte memberNodeSymbolPairs.First().node.FullSpan.Start, memberNodeSymbolPairs.Last().node.FullSpan.End); - // Can't extract to a new type if there's already a base. Maybe - // in the future we could inject a new type inbetween base and - // current - if (containingType.BaseType?.SpecialType != SpecialType.System_Object) + if (HasBaseType(containingType)) { - return null; + return (null, true); } var syntaxFacts = document.GetRequiredLanguageService(); @@ -104,32 +105,45 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte { // If the containing type node isn't found exit. This could be malformed code that we don't know // how to correctly handle - return null; + return (null, false); } if (selectedMemberNodes.Any(m => m.FirstAncestorOrSelf(syntaxFacts.IsTypeDeclaration) != containingTypeDeclarationNode)) { - return null; + return (null, false); } - return new ExtractClassWithDialogCodeAction( + var action = new ExtractClassWithDialogCodeAction( document, memberSpan, optionsService, containingType, containingTypeDeclarationNode, context.Options, selectedMembers); + + return (action, false); } private async Task TryGetClassActionAsync(CodeRefactoringContext context, IExtractClassOptionsService optionsService) { var selectedClassNode = await GetSelectedClassDeclarationAsync(context).ConfigureAwait(false); if (selectedClassNode is null) + { return null; + } var (document, span, cancellationToken) = context; var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); - if (semanticModel.GetDeclaredSymbol(selectedClassNode, cancellationToken) is not INamedTypeSymbol originalType) + if (semanticModel.GetDeclaredSymbol(selectedClassNode, cancellationToken) is not INamedTypeSymbol selectedType) + { return null; + } + + if (HasBaseType(selectedType)) + { + return null; + } return new ExtractClassWithDialogCodeAction( - document, span, optionsService, originalType, selectedClassNode, context.Options, selectedMembers: ImmutableArray.Empty); + document, span, optionsService, selectedType, selectedClassNode, context.Options, selectedMembers: ImmutableArray.Empty); } + + private static bool HasBaseType(INamedTypeSymbol containingType) => containingType.BaseType?.SpecialType != SpecialType.System_Object; } } diff --git a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.Analyzer.cs b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.Analyzer.cs index 743fe3c251dcd..519ce960d837e 100644 --- a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.Analyzer.cs +++ b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.Analyzer.cs @@ -252,7 +252,7 @@ private void WrapReturnTypeInTask(SemanticModel model, ref ITypeSymbol returnTyp var parameters = MarkVariableInfoToUseAsReturnValueIfPossible(GetMethodParameters(variableInfoMap.Values)); var variableToUseAsReturnValue = parameters.FirstOrDefault(v => v.UseAsReturnValue); var returnType = variableToUseAsReturnValue != null - ? variableToUseAsReturnValue.GetVariableType(_semanticDocument) + ? variableToUseAsReturnValue.GetVariableType() : compilation.GetSpecialType(SpecialType.System_Void); var unsafeAddressTakenUsed = ContainsVariableUnsafeAddressTaken(dataFlowAnalysisData, variableInfoMap.Keys); diff --git a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.AnalyzerResult.cs b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.AnalyzerResult.cs index 0612dfb286ba0..2268bd1f11655 100644 --- a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.AnalyzerResult.cs +++ b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.AnalyzerResult.cs @@ -35,17 +35,15 @@ public AnalyzerResult( bool endOfSelectionReachable, OperationStatus status) { - var semanticModel = document.SemanticModel; - UseInstanceMember = instanceMemberIsUsed; ShouldBeReadOnly = shouldBeReadOnly; EndOfSelectionReachable = endOfSelectionReachable; AwaitTaskReturn = awaitTaskReturn; SemanticDocument = document; - _typeParametersInDeclaration = typeParametersInDeclaration.Select(s => semanticModel.ResolveType(s)).ToList(); - _typeParametersInConstraintList = typeParametersInConstraintList.Select(s => semanticModel.ResolveType(s)).ToList(); + _typeParametersInDeclaration = typeParametersInDeclaration.ToList(); + _typeParametersInConstraintList = typeParametersInConstraintList.ToList(); _variables = variables; - ReturnType = semanticModel.ResolveType(returnType); + ReturnType = returnType; _variableToUseAsReturnValue = variableToUseAsReturnValue; Status = status; } diff --git a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.CodeGenerator.cs b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.CodeGenerator.cs index a4b6851e90720..b2b262321793e 100644 --- a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.CodeGenerator.cs +++ b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.CodeGenerator.cs @@ -350,7 +350,7 @@ protected ImmutableArray CreateMethodParameters() if (!isLocalFunction || !parameter.CanBeCapturedByLocalFunction) { var refKind = GetRefKind(parameter.ParameterModifier); - var type = parameter.GetVariableType(SemanticDocument); + var type = parameter.GetVariableType(); parameters.Add( CodeGenerationSymbolFactory.CreateParameterSymbol( diff --git a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.VariableInfo.cs b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.VariableInfo.cs index aa24d6f902298..622445d84d054 100644 --- a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.VariableInfo.cs +++ b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.VariableInfo.cs @@ -121,8 +121,8 @@ public bool CanBeCapturedByLocalFunction public ITypeSymbol OriginalType => _variableSymbol.OriginalType; - public ITypeSymbol GetVariableType(SemanticDocument document) - => document.SemanticModel.ResolveType(_variableSymbol.OriginalType); + public ITypeSymbol GetVariableType() + => _variableSymbol.OriginalType; public SyntaxToken GetIdentifierTokenAtDeclaration(SemanticDocument document) => document.GetTokenWithAnnotation(_variableSymbol.IdentifierTokenAnnotation); @@ -130,6 +130,8 @@ public SyntaxToken GetIdentifierTokenAtDeclaration(SemanticDocument document) public SyntaxToken GetIdentifierTokenAtDeclaration(SyntaxNode node) => node.GetAnnotatedTokens(_variableSymbol.IdentifierTokenAnnotation).SingleOrDefault(); + public SyntaxToken GetOriginalIdentifierToken(CancellationToken cancellationToken) => _variableSymbol.GetOriginalIdentifierToken(cancellationToken); + public static void SortVariables(Compilation compilation, ArrayBuilder variables) { var cancellationTokenType = compilation.GetTypeByMetadataName(typeof(CancellationToken).FullName); diff --git a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.VariableSymbol.cs b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.VariableSymbol.cs index cbf2d3f990661..fcaef9fcbd2f7 100644 --- a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.VariableSymbol.cs +++ b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.VariableSymbol.cs @@ -91,7 +91,7 @@ public override bool GetUseSaferDeclarationBehavior(CancellationToken cancellati } public override SyntaxToken GetOriginalIdentifierToken(CancellationToken cancellationToken) - => throw ExceptionUtilities.Unreachable(); + => default; public override SyntaxAnnotation IdentifierTokenAnnotation => throw ExceptionUtilities.Unreachable(); diff --git a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.cs b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.cs index af4564a992731..35e8e4573bcb5 100644 --- a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.cs +++ b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.cs @@ -173,7 +173,7 @@ private async Task> TryCheckVariableTypeAsync( foreach (var variable in variables) { - var originalType = variable.GetVariableType(document); + var originalType = variable.GetVariableType(); var result = await CheckTypeAsync(document.Document, contextNode, location, originalType, cancellationToken).ConfigureAwait(false); if (result.FailedWithNoBestEffortSuggestion()) { diff --git a/src/Features/Core/Portable/MakeMethodAsynchronous/AbstractMakeMethodAsynchronousCodeFixProvider.KnownTypes.cs b/src/Features/Core/Portable/MakeMethodAsynchronous/AbstractMakeMethodAsynchronousCodeFixProvider.KnownTypes.cs index f902bc85c9c60..b150685e6eb9d 100644 --- a/src/Features/Core/Portable/MakeMethodAsynchronous/AbstractMakeMethodAsynchronousCodeFixProvider.KnownTypes.cs +++ b/src/Features/Core/Portable/MakeMethodAsynchronous/AbstractMakeMethodAsynchronousCodeFixProvider.KnownTypes.cs @@ -12,29 +12,29 @@ internal abstract partial class AbstractMakeMethodAsynchronousCodeFixProvider { internal readonly struct KnownTypes { - public readonly INamedTypeSymbol _taskType; - public readonly INamedTypeSymbol _taskOfTType; - public readonly INamedTypeSymbol _valueTaskType; - public readonly INamedTypeSymbol _valueTaskOfTTypeOpt; + public readonly INamedTypeSymbol TaskType; + public readonly INamedTypeSymbol TaskOfTType; + public readonly INamedTypeSymbol ValueTaskType; + public readonly INamedTypeSymbol ValueTaskOfTTypeOpt; - public readonly INamedTypeSymbol _iEnumerableOfTType; - public readonly INamedTypeSymbol _iEnumeratorOfTType; + public readonly INamedTypeSymbol IEnumerableOfTType; + public readonly INamedTypeSymbol IEnumeratorOfTType; - public readonly INamedTypeSymbol _iAsyncEnumerableOfTTypeOpt; - public readonly INamedTypeSymbol _iAsyncEnumeratorOfTTypeOpt; + public readonly INamedTypeSymbol IAsyncEnumerableOfTTypeOpt; + public readonly INamedTypeSymbol IAsyncEnumeratorOfTTypeOpt; internal KnownTypes(Compilation compilation) { - _taskType = compilation.TaskType(); - _taskOfTType = compilation.TaskOfTType(); - _valueTaskType = compilation.ValueTaskType(); - _valueTaskOfTTypeOpt = compilation.ValueTaskOfTType(); + TaskType = compilation.TaskType(); + TaskOfTType = compilation.TaskOfTType(); + ValueTaskType = compilation.ValueTaskType(); + ValueTaskOfTTypeOpt = compilation.ValueTaskOfTType(); - _iEnumerableOfTType = compilation.IEnumerableOfTType(); - _iEnumeratorOfTType = compilation.IEnumeratorOfTType(); + IEnumerableOfTType = compilation.IEnumerableOfTType(); + IEnumeratorOfTType = compilation.IEnumeratorOfTType(); - _iAsyncEnumerableOfTTypeOpt = compilation.IAsyncEnumerableOfTType(); - _iAsyncEnumeratorOfTTypeOpt = compilation.IAsyncEnumeratorOfTType(); + IAsyncEnumerableOfTTypeOpt = compilation.IAsyncEnumerableOfTType(); + IAsyncEnumeratorOfTTypeOpt = compilation.IAsyncEnumeratorOfTType(); } } } diff --git a/src/Features/Core/Portable/MakeMethodAsynchronous/AbstractMakeMethodAsynchronousCodeFixProvider.cs b/src/Features/Core/Portable/MakeMethodAsynchronous/AbstractMakeMethodAsynchronousCodeFixProvider.cs index a0e7ab44d7826..dec466df4a7e8 100644 --- a/src/Features/Core/Portable/MakeMethodAsynchronous/AbstractMakeMethodAsynchronousCodeFixProvider.cs +++ b/src/Features/Core/Portable/MakeMethodAsynchronous/AbstractMakeMethodAsynchronousCodeFixProvider.cs @@ -48,7 +48,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) // if our member is already Task-Like, and that functionality recognizes // ValueTask if it is available, but does not care if it is not. var knownTypes = new KnownTypes(compilation); - if (knownTypes._taskType == null || knownTypes._taskOfTType == null) + if (knownTypes.TaskType == null || knownTypes.TaskOfTType == null) { return; } @@ -206,22 +206,22 @@ private async Task AddAsyncTokenAsync( protected static bool IsTaskLike(ITypeSymbol returnType, KnownTypes knownTypes) { - if (returnType.Equals(knownTypes._taskType)) + if (returnType.Equals(knownTypes.TaskType)) { return true; } - if (returnType.Equals(knownTypes._valueTaskType)) + if (returnType.Equals(knownTypes.ValueTaskType)) { return true; } - if (returnType.OriginalDefinition.Equals(knownTypes._taskOfTType)) + if (returnType.OriginalDefinition.Equals(knownTypes.TaskOfTType)) { return true; } - if (returnType.OriginalDefinition.Equals(knownTypes._valueTaskOfTTypeOpt)) + if (returnType.OriginalDefinition.Equals(knownTypes.ValueTaskOfTTypeOpt)) { return true; } diff --git a/src/Features/Core/Portable/Microsoft.CodeAnalysis.Features.csproj b/src/Features/Core/Portable/Microsoft.CodeAnalysis.Features.csproj index c1b3984e33fd1..424094ebf80b3 100644 --- a/src/Features/Core/Portable/Microsoft.CodeAnalysis.Features.csproj +++ b/src/Features/Core/Portable/Microsoft.CodeAnalysis.Features.csproj @@ -138,7 +138,7 @@ WARNING: All package references must have an OSS license since this assembly is shipped with dotnet-watch and dotnet-format. --> - + diff --git a/src/Features/Core/Portable/RemoveAsyncModifier/AbstractRemoveAsyncModifierCodeFixProvider.cs b/src/Features/Core/Portable/RemoveAsyncModifier/AbstractRemoveAsyncModifierCodeFixProvider.cs index 529c5846e65c0..a89fcf42828db 100644 --- a/src/Features/Core/Portable/RemoveAsyncModifier/AbstractRemoveAsyncModifierCodeFixProvider.cs +++ b/src/Features/Core/Portable/RemoveAsyncModifier/AbstractRemoveAsyncModifierCodeFixProvider.cs @@ -2,7 +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.Immutable; using System.Diagnostics; using System.Linq; @@ -104,12 +103,12 @@ protected sealed override async Task FixAllAsync( private static bool ShouldOfferFix(ITypeSymbol returnType, KnownTypes knownTypes) => IsTaskType(returnType, knownTypes) - || returnType.OriginalDefinition.Equals(knownTypes._taskOfTType) - || returnType.OriginalDefinition.Equals(knownTypes._valueTaskOfTTypeOpt); + || returnType.OriginalDefinition.Equals(knownTypes.TaskOfTType) + || returnType.OriginalDefinition.Equals(knownTypes.ValueTaskOfTTypeOpt); private static bool IsTaskType(ITypeSymbol returnType, KnownTypes knownTypes) - => returnType.OriginalDefinition.Equals(knownTypes._taskType) - || returnType.OriginalDefinition.Equals(knownTypes._valueTaskType); + => returnType.OriginalDefinition.Equals(knownTypes.TaskType) + || returnType.OriginalDefinition.Equals(knownTypes.ValueTaskType); private SyntaxNode RemoveAsyncModifier(SyntaxGenerator generator, SyntaxNode node, ITypeSymbol returnType, KnownTypes knownTypes, bool needsReturnStatementAdded) { @@ -200,14 +199,14 @@ private SyntaxNode ChangeReturnStatements(SyntaxGenerator generator, SyntaxNode private static SyntaxNode GetReturnTaskCompletedTaskStatement(SyntaxGenerator generator, ITypeSymbol returnType, KnownTypes knownTypes) { SyntaxNode invocation; - if (returnType.OriginalDefinition.Equals(knownTypes._taskType)) + if (returnType.OriginalDefinition.Equals(knownTypes.TaskType)) { - var taskTypeExpression = TypeExpressionForStaticMemberAccess(generator, knownTypes._taskType); + var taskTypeExpression = TypeExpressionForStaticMemberAccess(generator, knownTypes.TaskType); invocation = generator.MemberAccessExpression(taskTypeExpression, nameof(Task.CompletedTask)); } else { - invocation = generator.ObjectCreationExpression(knownTypes._valueTaskType); + invocation = generator.ObjectCreationExpression(knownTypes.ValueTaskType); } var statement = generator.ReturnStatement(invocation); @@ -216,10 +215,12 @@ private static SyntaxNode GetReturnTaskCompletedTaskStatement(SyntaxGenerator ge private static SyntaxNode WrapExpressionWithTaskFromResult(SyntaxGenerator generator, SyntaxNode expression, ITypeSymbol returnType, KnownTypes knownTypes) { - if (returnType.OriginalDefinition.Equals(knownTypes._taskOfTType)) + if (returnType.OriginalDefinition.Equals(knownTypes.TaskOfTType)) { - var taskTypeExpression = TypeExpressionForStaticMemberAccess(generator, knownTypes._taskType); - var taskFromResult = generator.MemberAccessExpression(taskTypeExpression, nameof(Task.FromResult)); + var taskTypeExpression = TypeExpressionForStaticMemberAccess(generator, knownTypes.TaskType); + var unwrappedReturnType = returnType.GetTypeArguments()[0]; + var memberName = generator.GenericName(nameof(Task.FromResult), unwrappedReturnType); + var taskFromResult = generator.MemberAccessExpression(taskTypeExpression, memberName); return generator.InvocationExpression(taskFromResult, expression.WithoutTrivia()).WithTriviaFrom(expression); } else diff --git a/src/Features/Core/Portable/Rename/SymbolicRenameInfo.cs b/src/Features/Core/Portable/Rename/SymbolicRenameInfo.cs index d6bc661f19c19..ed8c79f41fdf9 100644 --- a/src/Features/Core/Portable/Rename/SymbolicRenameInfo.cs +++ b/src/Features/Core/Portable/Rename/SymbolicRenameInfo.cs @@ -226,8 +226,9 @@ private static async Task GetRenameInfoAsync( if (sourceDocument is SourceGeneratedDocument) { - // The file is generated so we can't go editing it (for now) - return new SymbolicRenameInfo(FeaturesResources.You_cannot_rename_this_element); + // The file is generated so doesn't count towards valid spans + // we can edit. + continue; } if (document.Project.IsSubmission) @@ -249,6 +250,12 @@ private static async Task GetRenameInfoAsync( } } + // No valid spans available in source we can edit + if (documentSpans.Count == 0) + { + return new SymbolicRenameInfo(FeaturesResources.You_cannot_rename_this_element); + } + var sourceText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); var triggerText = sourceText.ToString(triggerToken.Span); diff --git a/src/Features/Core/Portable/SolutionCrawler/SolutionCrawlerService.cs b/src/Features/Core/Portable/SolutionCrawler/SolutionCrawlerService.cs index f59e2de1c947e..28dfa109aba43 100644 --- a/src/Features/Core/Portable/SolutionCrawler/SolutionCrawlerService.cs +++ b/src/Features/Core/Portable/SolutionCrawler/SolutionCrawlerService.cs @@ -13,8 +13,7 @@ namespace Microsoft.CodeAnalysis.SolutionCrawler { internal partial class SolutionCrawlerRegistrationService : ISolutionCrawlerRegistrationService { - internal static readonly Option2 EnableSolutionCrawler = new("InternalSolutionCrawlerOptions", "Solution Crawler", defaultValue: true, - storageLocation: new LocalUserProfileStorageLocation(@"Roslyn\Internal\SolutionCrawler\Solution Crawler")); + internal static readonly Option2 EnableSolutionCrawler = new("InternalSolutionCrawlerOptions_Solution Crawler", defaultValue: true); /// /// nested class of since it is tightly coupled with it. diff --git a/src/Features/Core/Portable/Wrapping/AbstractWrappingCodeRefactoringProvider.cs b/src/Features/Core/Portable/Wrapping/AbstractWrappingCodeRefactoringProvider.cs index 94b9c53458916..bea04ed452f91 100644 --- a/src/Features/Core/Portable/Wrapping/AbstractWrappingCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/Wrapping/AbstractWrappingCodeRefactoringProvider.cs @@ -9,6 +9,7 @@ using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Indentation; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.Wrapping @@ -32,7 +33,7 @@ protected AbstractWrappingCodeRefactoringProvider( _wrappers = wrappers; } - protected abstract SyntaxWrappingOptions GetWrappingOptions(AnalyzerConfigOptions options, CodeActionOptions ideOptions); + protected abstract SyntaxWrappingOptions GetWrappingOptions(IOptionsReader options, CodeActionOptions ideOptions); public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf index c92101ca3b79e..5638fb514dbb3 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf @@ -497,7 +497,7 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn Code snippet for '{0}' - Code snippet for '{0}' + Fragment kódu pro {0} @@ -982,7 +982,7 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn Inline temporary variable - Inline temporary variable + Dočasná vložená proměnná @@ -1302,7 +1302,7 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn Please resolve errors in your code before renaming this element. - Please resolve errors in your code before renaming this element. + Před přejmenováním tohoto elementu prosím vyřešte chyby v kódu. @@ -2557,7 +2557,7 @@ Pozitivní kontrolní výrazy zpětného vyhledávání s nulovou délkou se obv Renaming anonymous type members is not yet supported. - Renaming anonymous type members is not yet supported. + Přejmenování členů anonymního typu se zatím nepodporuje. @@ -3022,27 +3022,27 @@ Pozitivní kontrolní výrazy zpětného vyhledávání s nulovou délkou se obv You cannot rename elements from previous submissions. - You cannot rename elements from previous submissions. + Nemůžete přejmenovat elementy z předchozích odeslání. You cannot rename elements that are defined in metadata. - You cannot rename elements that are defined in metadata. + Nemůžete přejmenovat elementy, které jsou definované v metadatech. You cannot rename operators. - You cannot rename operators. + Nemůžete přejmenovat operátory. You cannot rename this element. - You cannot rename this element. + Nemůžete přejmenovat tento element. You must rename an identifier. - You must rename an identifier. + Musíte přejmenovat identifikátor. @@ -3465,7 +3465,7 @@ Pokud se specifikátor formátu d použije bez dalších specifikátorů vlastn else statement - else statement + příkaz else @@ -4994,7 +4994,7 @@ Posun se vždy zobrazuje se znaménkem na začátku. Znaménko plus (+) označuj while loop - while loop + smyčka while diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf index abb7e45edc7ee..83413282be964 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf @@ -497,7 +497,7 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d Code snippet for '{0}' - Code snippet for '{0}' + Codeschnipsel für „{0}“ @@ -982,7 +982,7 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d Inline temporary variable - Inline temporary variable + Inline temporär variabel @@ -1302,7 +1302,7 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d Please resolve errors in your code before renaming this element. - Please resolve errors in your code before renaming this element. + Beheben Sie die Fehler in Ihrem Code, bevor Sie dieses Element umbenennen. @@ -2557,7 +2557,7 @@ Positive Lookbehindassertionen mit Nullbreite werden normalerweise am Anfang reg Renaming anonymous type members is not yet supported. - Renaming anonymous type members is not yet supported. + Das Umbenennen von Elementen des Typs anonym wird noch nicht unterstützt. @@ -3022,27 +3022,27 @@ Positive Lookbehindassertionen mit Nullbreite werden normalerweise am Anfang reg You cannot rename elements from previous submissions. - You cannot rename elements from previous submissions. + Sie können Elemente aus vorherigen Übermittlungen umbenennen. You cannot rename elements that are defined in metadata. - You cannot rename elements that are defined in metadata. + Sie können in Metadaten definierte Elemente nicht umbenennen. You cannot rename operators. - You cannot rename operators. + Sie können Operatoren nicht umbenennen. You cannot rename this element. - You cannot rename this element. + Sie können dieses Element nicht umbenennen. You must rename an identifier. - You must rename an identifier. + Sie müssen einen Bezeichner umbenennen. @@ -3465,7 +3465,7 @@ Bei Verwendung des Formatbezeichners "d" ohne weitere benutzerdefinierte Formatb else statement - else statement + „else“-Anweisung @@ -4994,7 +4994,7 @@ Die Abweichung wird immer mit einem Vorzeichen angezeigt. Ein Pluszeichen (+) st while loop - while loop + „while“-Schleife diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf index 7b972c2991656..2028ab9bc632d 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf @@ -497,7 +497,7 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa Code snippet for '{0}' - Code snippet for '{0}' + Fragmento de código para “{0}” @@ -982,7 +982,7 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa Inline temporary variable - Inline temporary variable + Variable temporal en línea @@ -1302,7 +1302,7 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa Please resolve errors in your code before renaming this element. - Please resolve errors in your code before renaming this element. + Resuelva los errores del código antes de cambiar el nombre de este elemento. @@ -2557,7 +2557,7 @@ Las aserciones de búsqueda retrasada (lookbehind) positivas de ancho cero se us Renaming anonymous type members is not yet supported. - Renaming anonymous type members is not yet supported. + Todavía no se puede cambiar el nombre de miembros de tipo anónimo. @@ -3022,27 +3022,27 @@ Las aserciones de búsqueda retrasada (lookbehind) positivas de ancho cero se us You cannot rename elements from previous submissions. - You cannot rename elements from previous submissions. + No se puede cambiar el nombre a elementos de envíos anteriores. You cannot rename elements that are defined in metadata. - You cannot rename elements that are defined in metadata. + No se puede cambiar el nombre a elementos que están definidos en metadatos. You cannot rename operators. - You cannot rename operators. + No se puede cambiar el nombre a los operadores. You cannot rename this element. - You cannot rename this element. + No se puede cambiar el nombre a este elemento. You must rename an identifier. - You must rename an identifier. + Debe cambiar el nombre de un identificador. @@ -3465,7 +3465,7 @@ Si el especificador de formato "d" se usa sin otros especificadores de formato p else statement - else statement + Instrucción else @@ -4994,7 +4994,7 @@ El desfase se muestra siempre con un signo delante. Un signo más (+) indica las while loop - while loop + bucle while diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf index 2e7baa68a3557..6610b244c15c8 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf @@ -497,7 +497,7 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai Code snippet for '{0}' - Code snippet for '{0}' + Extrait de code pour '{0}' @@ -982,7 +982,7 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai Inline temporary variable - Inline temporary variable + Variable temporaire inline @@ -1302,7 +1302,7 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai Please resolve errors in your code before renaming this element. - Please resolve errors in your code before renaming this element. + Corrigez les erreurs dans votre code avant de renommer cet élément. @@ -2557,7 +2557,7 @@ Les assertions arrière positives de largeur nulle sont généralement utilisée Renaming anonymous type members is not yet supported. - Renaming anonymous type members is not yet supported. + Le changement de nom des membres de type anonyme n'est pas encore pris en charge. @@ -3022,27 +3022,27 @@ Les assertions arrière positives de largeur nulle sont généralement utilisée You cannot rename elements from previous submissions. - You cannot rename elements from previous submissions. + Vous ne pouvez pas renommer des éléments de soumissions précédentes. You cannot rename elements that are defined in metadata. - You cannot rename elements that are defined in metadata. + Vous ne pouvez pas renommer des éléments définis dans les métadonnées. You cannot rename operators. - You cannot rename operators. + Vous ne pouvez pas renommer des opérateurs. You cannot rename this element. - You cannot rename this element. + Vous ne pouvez pas renommer cet élément. You must rename an identifier. - You must rename an identifier. + Vous devez renommer un identificateur. @@ -3465,7 +3465,7 @@ Si le spécificateur de format "d" est utilisé sans autres spécificateurs de f else statement - else statement + instruction else @@ -4994,7 +4994,7 @@ Le décalage est toujours affiché avec un signe de début. Le signe plus (+) in while loop - while loop + pendant la boucle diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf index 46d5041cde927..41dd49cc9b2b9 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf @@ -497,7 +497,7 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa Code snippet for '{0}' - Code snippet for '{0}' + Frammento di codice per '{0}' @@ -982,7 +982,7 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa Inline temporary variable - Inline temporary variable + Variabile temporanea inline @@ -1302,7 +1302,7 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa Please resolve errors in your code before renaming this element. - Please resolve errors in your code before renaming this element. + Prima di rinominare l'elemento risolvere gli errori nel codice. @@ -2557,7 +2557,7 @@ Le asserzioni lookbehind positive di larghezza zero vengono usate in genere all' Renaming anonymous type members is not yet supported. - Renaming anonymous type members is not yet supported. + La ridenominazione di membri con tipo anonimo non è ancora supportata. @@ -3022,27 +3022,27 @@ Le asserzioni lookbehind positive di larghezza zero vengono usate in genere all' You cannot rename elements from previous submissions. - You cannot rename elements from previous submissions. + Non è possibile rinominare elementi di invii precedenti. You cannot rename elements that are defined in metadata. - You cannot rename elements that are defined in metadata. + Non è possibile rinominare elementi definiti nei metadati. You cannot rename operators. - You cannot rename operators. + Non è possibile rinominare gli operatori. You cannot rename this element. - You cannot rename this element. + Non è possibile rinominare questo elemento. You must rename an identifier. - You must rename an identifier. + È necessario rinominare un identificatore. @@ -3465,7 +3465,7 @@ Se l'identificatore di formato "d" viene usato senza altri identificatori di for else statement - else statement + istruzione else @@ -4994,7 +4994,7 @@ La differenza viene sempre visualizzata con un segno iniziale. Un segno più (+) while loop - while loop + ciclo while diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf index cb632320f8411..6ef6310119306 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf @@ -497,7 +497,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Code snippet for '{0}' - Code snippet for '{0}' + '{0}' のコード スニペット @@ -982,7 +982,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Inline temporary variable - Inline temporary variable + インラインの一時変数 @@ -1302,7 +1302,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Please resolve errors in your code before renaming this element. - Please resolve errors in your code before renaming this element. + この要素の名前を変更する前に、コード内のエラーを解決してください。 @@ -2557,7 +2557,7 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Renaming anonymous type members is not yet supported. - Renaming anonymous type members is not yet supported. + 匿名型メンバーの名前の変更は、まだサポートされていません。 @@ -3022,27 +3022,27 @@ Zero-width positive lookbehind assertions are typically used at the beginning of You cannot rename elements from previous submissions. - You cannot rename elements from previous submissions. + 前の送信からの要素の名前を変更することはできません。 You cannot rename elements that are defined in metadata. - You cannot rename elements that are defined in metadata. + メタデータで定義されている要素の名前を変更することはできません。 You cannot rename operators. - You cannot rename operators. + 演算子の名前を変更することはできません。 You cannot rename this element. - You cannot rename this element. + この要素の名前を変更することはできません。 You must rename an identifier. - You must rename an identifier. + 識別子の名前を変更する必要があります。 @@ -3465,7 +3465,7 @@ If the "d" format specifier is used without other custom format specifiers, it's else statement - else statement + else ステートメント @@ -4994,7 +4994,7 @@ DateTimeOffset 値で使用した場合、この書式指定子は DateTimeOffse while loop - while loop + while ループ diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf index 774a9b8c11a58..3e29651ac5585 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf @@ -497,7 +497,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Code snippet for '{0}' - Code snippet for '{0}' + '{0}'의 코드 조각 @@ -982,7 +982,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Inline temporary variable - Inline temporary variable + 인라인 임시 변수 @@ -1302,7 +1302,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Please resolve errors in your code before renaming this element. - Please resolve errors in your code before renaming this element. + 이 요소의 이름을 바꾸기 전에 코드 오류를 해결하세요. @@ -2557,7 +2557,7 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Renaming anonymous type members is not yet supported. - Renaming anonymous type members is not yet supported. + 익명 형식의 멤버 이름은 아직 바꿀 수 없습니다. @@ -3022,27 +3022,27 @@ Zero-width positive lookbehind assertions are typically used at the beginning of You cannot rename elements from previous submissions. - You cannot rename elements from previous submissions. + 이전 전송 요소의 이름을 바꿀 수 없습니다. You cannot rename elements that are defined in metadata. - You cannot rename elements that are defined in metadata. + 메타데이터에서 정의된 요소의 이름을 바꿀 수 없습니다. You cannot rename operators. - You cannot rename operators. + 연산자의 이름을 바꿀 수 없습니다. You cannot rename this element. - You cannot rename this element. + 이 요소의 이름을 바꿀 수 없습니다. You must rename an identifier. - You must rename an identifier. + 식별자의 이름을 바꿔야 합니다. @@ -4994,7 +4994,7 @@ DateTimeOffset 값의 경우, 이 형식 지정자는 UTC에서 가져온 DateTi while loop - while loop + while 루프 diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf index 2b687e2ea0818..76d858fc7147c 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf @@ -497,7 +497,7 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k Code snippet for '{0}' - Code snippet for '{0}' + Fragment kodu dla elementu „{0}” @@ -982,7 +982,7 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k Inline temporary variable - Inline temporary variable + Wstawiona zmienna tymczasowa @@ -1302,7 +1302,7 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k Please resolve errors in your code before renaming this element. - Please resolve errors in your code before renaming this element. + Przed zmianą nazwy tego elementu napraw problemy występujące w kodzie. @@ -2557,7 +2557,7 @@ Pozytywne asercje wsteczne o zerowej szerokości są zwykle używane na początk Renaming anonymous type members is not yet supported. - Renaming anonymous type members is not yet supported. + Zmienianie nazwy anonimowych składowych typu nie jest jeszcze obsługiwane. @@ -3022,27 +3022,27 @@ Pozytywne asercje wsteczne o zerowej szerokości są zwykle używane na początk You cannot rename elements from previous submissions. - You cannot rename elements from previous submissions. + Nie można zmienić nazw elementów pochodzących z poprzednich przesłanych elementów. You cannot rename elements that are defined in metadata. - You cannot rename elements that are defined in metadata. + Nie można zmienić nazw elementów zdefiniowanych w metadanych. You cannot rename operators. - You cannot rename operators. + Nie można zmienić nazw operatorów. You cannot rename this element. - You cannot rename this element. + Nie można zmienić nazwy tego elementu. You must rename an identifier. - You must rename an identifier. + Należy zmienić nazwę identyfikatora. @@ -4994,7 +4994,7 @@ Przesunięcie jest zawsze wyświetlane ze znakiem wiodącym. Znak plus (+) wskaz while loop - while loop + pętla while diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf index 83d9123eefb00..8c1b605841491 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf @@ -497,7 +497,7 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess Code snippet for '{0}' - Code snippet for '{0}' + Trecho de código para '{0}' @@ -982,7 +982,7 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess Inline temporary variable - Inline temporary variable + Variável temporária embutida @@ -1302,7 +1302,7 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess Please resolve errors in your code before renaming this element. - Please resolve errors in your code before renaming this element. + Resolva erros em seu código antes de renomear este elemento. @@ -2557,7 +2557,7 @@ As declarações de lookbehind positivas de largura zero normalmente são usadas Renaming anonymous type members is not yet supported. - Renaming anonymous type members is not yet supported. + Renomear membros de tipo anônimo ainda não é suportado. @@ -3022,27 +3022,27 @@ As declarações de lookbehind positivas de largura zero normalmente são usadas You cannot rename elements from previous submissions. - You cannot rename elements from previous submissions. + Você não pode renomear elementos de envios anteriores. You cannot rename elements that are defined in metadata. - You cannot rename elements that are defined in metadata. + Você não pode renomear elementos que estão definidos nos metadados. You cannot rename operators. - You cannot rename operators. + Você não pode renomear operadores. You cannot rename this element. - You cannot rename this element. + Você não pode renomear este elemento. You must rename an identifier. - You must rename an identifier. + Você deve renomear um identificador. @@ -3465,7 +3465,7 @@ Se o especificador de formato "d" for usado sem outros especificadores de format else statement - else statement + outra declaração @@ -4994,7 +4994,7 @@ O deslocamento é sempre exibido com um sinal à esquerda. Um sinal de adição while loop - while loop + loop while diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf index 0c2de9f21cf83..c98d59efd0911 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf @@ -497,7 +497,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Code snippet for '{0}' - Code snippet for '{0}' + Фрагмент кода для "{0}" @@ -982,7 +982,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Inline temporary variable - Inline temporary variable + Встроить временную переменную @@ -1302,7 +1302,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Please resolve errors in your code before renaming this element. - Please resolve errors in your code before renaming this element. + Устраните ошибки в коде, прежде чем переименовать этот элемент. @@ -2557,7 +2557,7 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Renaming anonymous type members is not yet supported. - Renaming anonymous type members is not yet supported. + Переименование членов анонимного типа еще не поддерживается. @@ -3022,27 +3022,27 @@ Zero-width positive lookbehind assertions are typically used at the beginning of You cannot rename elements from previous submissions. - You cannot rename elements from previous submissions. + Нельзя переименовать элементы из предыдущих отправок. You cannot rename elements that are defined in metadata. - You cannot rename elements that are defined in metadata. + Нельзя переименовать элементы, определенные в метаданных. You cannot rename operators. - You cannot rename operators. + Нельзя переименовать операторы. You cannot rename this element. - You cannot rename this element. + Этот элемент переименовать нельзя. You must rename an identifier. - You must rename an identifier. + Необходимо переименовать идентификатор. @@ -3465,7 +3465,7 @@ If the "d" format specifier is used without other custom format specifiers, it's else statement - else statement + инструкция else @@ -4994,7 +4994,7 @@ The offset is always displayed with a leading sign. A plus sign (+) indicates ho while loop - while loop + Цикл while diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf index f8b1fe186d918..e365f954fa1d8 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf @@ -497,7 +497,7 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be Code snippet for '{0}' - Code snippet for '{0}' + '{0}' için kod parçacığı @@ -982,7 +982,7 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be Inline temporary variable - Inline temporary variable + Satır içi geçici değişken @@ -1302,7 +1302,7 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be Please resolve errors in your code before renaming this element. - Please resolve errors in your code before renaming this element. + Bu öğeyi yeniden adlandırmadan önce lütfen kodunuzdaki hataları çözümleyin. @@ -2557,7 +2557,7 @@ Sıfır genişlikli pozitif geri yönlü onaylamalar genellikle normal ifadeleri Renaming anonymous type members is not yet supported. - Renaming anonymous type members is not yet supported. + Anonim türdeki üyeleri yeniden adlandırma henüz desteklenmiyor. @@ -3022,27 +3022,27 @@ Sıfır genişlikli pozitif geri yönlü onaylamalar genellikle normal ifadeleri You cannot rename elements from previous submissions. - You cannot rename elements from previous submissions. + Öğeleri önceki gönderimlerden yeniden adlandıramazsınız. You cannot rename elements that are defined in metadata. - You cannot rename elements that are defined in metadata. + Meta verilerde tanımlanan öğeleri yeniden adlandıramazsınız. You cannot rename operators. - You cannot rename operators. + Operatörleri yeniden adlandıramazsınız. You cannot rename this element. - You cannot rename this element. + Bu öğeyi yeniden adlandıramazsınız. You must rename an identifier. - You must rename an identifier. + Bir tanımlayıcıyı yeniden adlandırmalısınız. @@ -3465,7 +3465,7 @@ If the "d" format specifier is used without other custom format specifiers, it's else statement - else statement + else deyimi @@ -4994,7 +4994,7 @@ Uzaklık her zaman başında bir işaretle görüntülenir. Artı işareti (+) U while loop - while loop + while döngüsü diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf index ee1d91bd39652..258c21fc718bb 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf @@ -497,7 +497,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Code snippet for '{0}' - Code snippet for '{0}' + "{0}" 的代码片段 @@ -982,7 +982,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Inline temporary variable - Inline temporary variable + 内联临时变量 @@ -1302,7 +1302,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Please resolve errors in your code before renaming this element. - Please resolve errors in your code before renaming this element. + 请在重命名此元素前解决代码中的错误。 @@ -2557,7 +2557,7 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Renaming anonymous type members is not yet supported. - Renaming anonymous type members is not yet supported. + 尚不支持重命名匿名类型成员。 @@ -3022,27 +3022,27 @@ Zero-width positive lookbehind assertions are typically used at the beginning of You cannot rename elements from previous submissions. - You cannot rename elements from previous submissions. + 无法重命名来自之前提交的元素。 You cannot rename elements that are defined in metadata. - You cannot rename elements that are defined in metadata. + 无法重命名元数据中定义的元素。 You cannot rename operators. - You cannot rename operators. + 无法重命名运算符。 You cannot rename this element. - You cannot rename this element. + 无法重命名此元素。 You must rename an identifier. - You must rename an identifier. + 必须重命名标识符。 @@ -3465,7 +3465,7 @@ If the "d" format specifier is used without other custom format specifiers, it's else statement - else statement + else 语句 @@ -4994,7 +4994,7 @@ The offset is always displayed with a leading sign. A plus sign (+) indicates ho while loop - while loop + while 循环 diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf index d6fdf26b280c5..88efa94ba05cb 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf @@ -497,7 +497,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Code snippet for '{0}' - Code snippet for '{0}' + '{0}' 的程式碼片段 @@ -982,7 +982,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Inline temporary variable - Inline temporary variable + 內嵌暫存變數 @@ -1302,7 +1302,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Please resolve errors in your code before renaming this element. - Please resolve errors in your code before renaming this element. + 請先解決程式碼中的錯誤,再重新命名此元素。 @@ -2557,7 +2557,7 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Renaming anonymous type members is not yet supported. - Renaming anonymous type members is not yet supported. + 目前尚不支援重新命名匿名類型成員。 @@ -3022,27 +3022,27 @@ Zero-width positive lookbehind assertions are typically used at the beginning of You cannot rename elements from previous submissions. - You cannot rename elements from previous submissions. + 您無法重新命名上次提交的元素。 You cannot rename elements that are defined in metadata. - You cannot rename elements that are defined in metadata. + 您無法重新命名中繼資料中所定義的元素。 You cannot rename operators. - You cannot rename operators. + 您無法重新命名運算子。 You cannot rename this element. - You cannot rename this element. + 您無法重新命名此元素。 You must rename an identifier. - You must rename an identifier. + 您必須重新命名識別項。 @@ -3465,7 +3465,7 @@ If the "d" format specifier is used without other custom format specifiers, it's else statement - else statement + else 陳述式 @@ -4994,7 +4994,7 @@ The offset is always displayed with a leading sign. A plus sign (+) indicates ho while loop - while loop + while 迴圈 diff --git a/src/Features/LanguageServer/Microsoft.CodeAnalysis.CSharp.LanguageServer.Protocol/Microsoft.CodeAnalysis.CSharp.LanguageServer.Protocol.csproj b/src/Features/LanguageServer/Microsoft.CodeAnalysis.CSharp.LanguageServer.Protocol/Microsoft.CodeAnalysis.CSharp.LanguageServer.Protocol.csproj deleted file mode 100644 index f3385e7a2bc1e..0000000000000 --- a/src/Features/LanguageServer/Microsoft.CodeAnalysis.CSharp.LanguageServer.Protocol/Microsoft.CodeAnalysis.CSharp.LanguageServer.Protocol.csproj +++ /dev/null @@ -1,28 +0,0 @@ - - - - - Library - Microsoft.CodeAnalysis.CSharp.LanguageServer - netcoreapp3.1;netstandard2.0 - true - - .NET Compiler Platform ("Roslyn") support for Language Server Protocol in CSharp. - - - - - - - - - - - - - - - diff --git a/src/Features/LanguageServer/Microsoft.CodeAnalysis.VisualBasic.LanguageServer.Protocol/Microsoft.CodeAnalysis.VisualBasic.LanguageServer.Protocol.vbproj b/src/Features/LanguageServer/Microsoft.CodeAnalysis.VisualBasic.LanguageServer.Protocol/Microsoft.CodeAnalysis.VisualBasic.LanguageServer.Protocol.vbproj deleted file mode 100644 index 5651558331b7c..0000000000000 --- a/src/Features/LanguageServer/Microsoft.CodeAnalysis.VisualBasic.LanguageServer.Protocol/Microsoft.CodeAnalysis.VisualBasic.LanguageServer.Protocol.vbproj +++ /dev/null @@ -1,28 +0,0 @@ - - - - Library - Microsoft.CodeAnalysis.VisualBasic.LanguageServer - netcoreapp3.1;netstandard2.0 - true - - .NET Compiler Platform ("Roslyn") support for Language Server Protocol in Visual Basic. - - - - - - - - - - - - - - - - diff --git a/src/Features/LanguageServer/Protocol/Extensions/ProtocolConversions.cs b/src/Features/LanguageServer/Protocol/Extensions/ProtocolConversions.cs index db3bdf9c322dd..fe81f12a1f9b6 100644 --- a/src/Features/LanguageServer/Protocol/Extensions/ProtocolConversions.cs +++ b/src/Features/LanguageServer/Protocol/Extensions/ProtocolConversions.cs @@ -12,6 +12,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.DocumentHighlighting; +using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Indentation; @@ -194,7 +195,16 @@ public static LinePositionSpan RangeToLinePositionSpan(LSP.Range range) public static TextSpan RangeToTextSpan(LSP.Range range, SourceText text) { var linePositionSpan = RangeToLinePositionSpan(range); - return text.Lines.GetTextSpan(linePositionSpan); + + try + { + return text.Lines.GetTextSpan(linePositionSpan); + } + // Temporary exception reporting to investigate https://github.com/dotnet/roslyn/issues/66258. + catch (Exception e) when (FatalError.ReportAndPropagate(e)) + { + throw; + } } public static LSP.TextEdit TextChangeToTextEdit(TextChange textChange, SourceText oldText) diff --git a/src/Features/LanguageServer/Protocol/ExternalAccess/VSCode/API/VSCodeAnalyzerLoader.cs b/src/Features/LanguageServer/Protocol/ExternalAccess/VSCode/API/VSCodeAnalyzerLoader.cs index 3d22abfadcac6..d4b31cfce7cb6 100644 --- a/src/Features/LanguageServer/Protocol/ExternalAccess/VSCode/API/VSCodeAnalyzerLoader.cs +++ b/src/Features/LanguageServer/Protocol/ExternalAccess/VSCode/API/VSCodeAnalyzerLoader.cs @@ -29,7 +29,7 @@ public VSCodeAnalyzerLoader(IDiagnosticAnalyzerService analyzerService, IDiagnos public void InitializeDiagnosticsServices(Workspace workspace) { - _globalOptionService.SetGlobalOption(new OptionKey(InternalDiagnosticsOptions.NormalDiagnosticMode), DiagnosticMode.LspPull); + _globalOptionService.SetGlobalOption(InternalDiagnosticsOptions.NormalDiagnosticMode, DiagnosticMode.LspPull); _ = ((IIncrementalAnalyzerProvider)_analyzerService).CreateIncrementalAnalyzer(workspace); _diagnosticService.Register((IDiagnosticUpdateSource)_analyzerService); } diff --git a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.AnalysisData.cs b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.AnalysisData.cs index d9c11caf65950..e72d4e5ade939 100644 --- a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.AnalysisData.cs +++ b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.AnalysisData.cs @@ -109,6 +109,9 @@ public ProjectAnalysisData( public DiagnosticAnalysisResult GetResult(DiagnosticAnalyzer analyzer) => GetResultOrEmpty(Result, analyzer, ProjectId, Version); + public bool TryGetResult(DiagnosticAnalyzer analyzer, out DiagnosticAnalysisResult result) + => Result.TryGetValue(analyzer, out result); + public static async Task CreateAsync(Project project, IEnumerable stateSets, bool avoidLoadingData, CancellationToken cancellationToken) { VersionStamp? version = null; diff --git a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.Executor.cs b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.Executor.cs index 5ec74f649933c..81cf37d95f12f 100644 --- a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.Executor.cs +++ b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.Executor.cs @@ -24,8 +24,10 @@ internal partial class DiagnosticIncrementalAnalyzer { /// /// Return all cached local diagnostics (syntax, semantic) that belong to given document for the given StateSet (analyzer). - /// Also returns empty diagnostics for suppressed analyzer. - /// Returns null if the diagnostics need to be computed. + /// Otherwise, return null. + /// For the latter case, indicates if the analyzer is suppressed + /// for the given document/project. If suppressed, the caller does not need to compute the diagnostics for the given + /// analyzer. Otherwise, diagnostics need to be computed. /// private DocumentAnalysisData? TryGetCachedDocumentAnalysisData( TextDocument document, StateSet stateSet, @@ -34,10 +36,13 @@ internal partial class DiagnosticIncrementalAnalyzer CompilerDiagnosticsScope compilerDiagnosticsScope, bool isActiveDocument, bool isVisibleDocument, bool isOpenDocument, bool isGeneratedRazorDocument, - CancellationToken cancellationToken) + CancellationToken cancellationToken, + out bool isAnalyzerSuppressed) { Debug.Assert(isActiveDocument || isOpenDocument || isGeneratedRazorDocument); + isAnalyzerSuppressed = false; + try { var state = stateSet.GetOrCreateActiveFileState(document.Id); @@ -48,14 +53,13 @@ internal partial class DiagnosticIncrementalAnalyzer return existingData; } - // Perf optimization: Check whether analyzer is suppressed for project or document and avoid getting diagnostics if suppressed. - if (!DocumentAnalysisExecutor.IsAnalyzerEnabledForProject(stateSet.Analyzer, document.Project, GlobalOptions) || + // Check whether analyzer is suppressed for project or document. + // If so, we set the flag indicating that the client can skip analysis for this document. + // Regardless of whether or not the analyzer is suppressed for project or document, + // we return null to indicate that no diagnostics are cached for this document for the given version. + isAnalyzerSuppressed = !DocumentAnalysisExecutor.IsAnalyzerEnabledForProject(stateSet.Analyzer, document.Project, GlobalOptions) || !IsAnalyzerEnabledForDocument(stateSet.Analyzer, existingData, analysisScope, compilerDiagnosticsScope, - isActiveDocument, isVisibleDocument, isOpenDocument, isGeneratedRazorDocument)) - { - return new DocumentAnalysisData(version, existingData.Items, ImmutableArray.Empty); - } - + isActiveDocument, isVisibleDocument, isOpenDocument, isGeneratedRazorDocument); return null; } catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) diff --git a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.ProjectState.cs b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.ProjectState.cs index 8390d92936547..db3c640b1f33d 100644 --- a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.ProjectState.cs +++ b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.ProjectState.cs @@ -256,8 +256,7 @@ public async ValueTask MergeAsync(ActiveFileState state, TextDocument document, // keep from build flag if full analysis is off var fromBuild = fullAnalysis ? false : lastResult.FromBuild; - var languageServices = document.Project.Services; - var simplifierOptions = (languageServices.GetService() != null) ? globalOptions.GetSimplifierOptions(languageServices) : null; + var simplifierOptions = globalOptions.GetSimplifierOptions(document.Project.Services); var openFileOnlyAnalyzer = _owner.Analyzer.IsOpenFileOnly(simplifierOptions); // if it is allowed to keep project state, check versions and if they are same, bail out. diff --git a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.cs b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.cs index cb621104e078c..5c84c01556571 100644 --- a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.cs +++ b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.cs @@ -70,8 +70,8 @@ public DiagnosticIncrementalAnalyzer( private void OnGlobalOptionChanged(object? sender, OptionChangedEventArgs e) { - if (e.Option.Feature == nameof(SimplificationOptions) || - e.Option.Feature == nameof(CodeStyleOptions) || + if (e.Option == NamingStyleOptions.NamingPreferences || + e.Option.Definition.Group.Parent == CodeStyleOptionGroups.CodeStyle || e.Option == SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption || e.Option == SolutionCrawlerOptionsStorage.SolutionBackgroundAnalysisScopeOption || e.Option == SolutionCrawlerOptionsStorage.CompilerDiagnosticsScopeOption) diff --git a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs index 8406732d9f5a6..0f2812ab15d17 100644 --- a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs +++ b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs @@ -13,7 +13,6 @@ using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.SolutionCrawler; using Microsoft.CodeAnalysis.Workspaces.Diagnostics; using Roslyn.Utilities; @@ -73,13 +72,12 @@ private async Task AnalyzeDocumentForKindAsync(TextDocument document, AnalysisKi { var data = TryGetCachedDocumentAnalysisData(document, stateSet, kind, version, backgroundAnalysisScope, compilerDiagnosticsScope, isActiveDocument, isVisibleDocument, - isOpenDocument, isGeneratedRazorDocument, cancellationToken); + isOpenDocument, isGeneratedRazorDocument, cancellationToken, out var isAnalyzerSuppressed); if (data.HasValue) { - // We need to persist and raise diagnostics for suppressed analyzer. PersistAndRaiseDiagnosticsIfNeeded(data.Value, stateSet); } - else + else if (!isAnalyzerSuppressed) { nonCachedStateSets.Add(stateSet); } @@ -156,23 +154,25 @@ private async Task AnalyzeProjectAsync(Project project, bool forceAnalyzerRun, C } var result = await GetProjectAnalysisDataAsync(compilationWithAnalyzers, project, ideOptions, stateSets, forceAnalyzerRun, cancellationToken).ConfigureAwait(false); - if (result.OldResult == null) - { - RaiseProjectDiagnosticsIfNeeded(project, stateSets, result.Result); - return; - } // no cancellation after this point. - // any analyzer that doesn't have result will be treated as returned empty set - // which means we will remove those from error list + using var _ = ArrayBuilder.GetInstance(out var analyzedStateSetsBuilder); foreach (var stateSet in stateSets) { var state = stateSet.GetOrCreateProjectState(project.Id); - await state.SaveToInMemoryStorageAsync(project, result.GetResult(stateSet.Analyzer)).ConfigureAwait(false); + if (result.TryGetResult(stateSet.Analyzer, out var analyzerResult)) + { + await state.SaveToInMemoryStorageAsync(project, analyzerResult).ConfigureAwait(false); + analyzedStateSetsBuilder.Add(stateSet); + } } - RaiseProjectDiagnosticsIfNeeded(project, stateSets, result.OldResult, result.Result); + if (analyzedStateSetsBuilder.Count > 0) + { + var oldResult = result.OldResult ?? ImmutableDictionary.Empty; + RaiseProjectDiagnosticsIfNeeded(project, analyzedStateSetsBuilder.ToImmutable(), oldResult, result.Result); + } } catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { diff --git a/src/Features/LanguageServer/Protocol/Features/Options/AddImportPlacementOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/AddImportPlacementOptionsStorage.cs index a43e2f198fab8..c9b94fd3d9ebc 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/AddImportPlacementOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/AddImportPlacementOptionsStorage.cs @@ -9,16 +9,14 @@ namespace Microsoft.CodeAnalysis.AddImport; -internal interface IAddImportPlacementOptionsStorage : ILanguageService -{ - AddImportPlacementOptions GetOptions(IGlobalOptionService globalOptions); -} - internal static class AddImportPlacementOptionsStorage { public static ValueTask GetAddImportPlacementOptionsAsync(this Document document, IGlobalOptionService globalOptions, CancellationToken cancellationToken) => document.GetAddImportPlacementOptionsAsync(globalOptions.GetAddImportPlacementOptions(document.Project.Services), cancellationToken); public static AddImportPlacementOptions GetAddImportPlacementOptions(this IGlobalOptionService globalOptions, LanguageServices languageServices) - => languageServices.GetRequiredService().GetOptions(globalOptions); + => languageServices.GetRequiredService().GetAddImportOptions( + globalOptions, + allowInHiddenRegions: AddImportPlacementOptions.Default.AllowInHiddenRegions, // no global option available + fallbackOptions: null); } diff --git a/src/Features/LanguageServer/Protocol/Features/Options/AutoFormattingOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/AutoFormattingOptionsStorage.cs index ebb32d1132da0..af136c970e369 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/AutoFormattingOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/AutoFormattingOptionsStorage.cs @@ -18,18 +18,14 @@ public static AutoFormattingOptions GetAutoFormattingOptions(this IGlobalOptionS }; internal static readonly PerLanguageOption2 FormatOnReturn = new( - "FormattingOptions", OptionGroup.Default, "AutoFormattingOnReturn", AutoFormattingOptions.Default.FormatOnReturn, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.Auto Formatting On Return")); + "FormattingOptions_AutoFormattingOnReturn", AutoFormattingOptions.Default.FormatOnReturn); public static readonly PerLanguageOption2 FormatOnTyping = new( - "FormattingOptions", OptionGroup.Default, "AutoFormattingOnTyping", AutoFormattingOptions.Default.FormatOnTyping, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.Auto Formatting On Typing")); + "FormattingOptions_AutoFormattingOnTyping", AutoFormattingOptions.Default.FormatOnTyping); public static readonly PerLanguageOption2 FormatOnSemicolon = new( - "FormattingOptions", OptionGroup.Default, "AutoFormattingOnSemicolon", AutoFormattingOptions.Default.FormatOnSemicolon, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.Auto Formatting On Semicolon")); + "FormattingOptions_AutoFormattingOnSemicolon", AutoFormattingOptions.Default.FormatOnSemicolon); public static readonly PerLanguageOption2 FormatOnCloseBrace = new( - "BraceCompletionOptions", "AutoFormattingOnCloseBrace", defaultValue: AutoFormattingOptions.Default.FormatOnCloseBrace, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.Auto Formatting On Close Brace")); + "BraceCompletionOptions_AutoFormattingOnCloseBrace", AutoFormattingOptions.Default.FormatOnCloseBrace); } diff --git a/src/Features/LanguageServer/Protocol/Features/Options/BlockStructureOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/BlockStructureOptionsStorage.cs index 5416070de84c6..2ddac1ad8a655 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/BlockStructureOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/BlockStructureOptionsStorage.cs @@ -29,52 +29,39 @@ public static BlockStructureOptions GetBlockStructureOptions(this IGlobalOptionS IsMetadataAsSource = isMetadataAsSource, }; - private const string FeatureName = "BlockStructureOptions"; - public static readonly PerLanguageOption2 ShowBlockStructureGuidesForCommentsAndPreprocessorRegions = new( - FeatureName, "ShowBlockStructureGuidesForCommentsAndPreprocessorRegions", BlockStructureOptions.Default.ShowBlockStructureGuidesForCommentsAndPreprocessorRegions, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ShowBlockStructureGuidesForCommentsAndPreprocessorRegions")); + "BlockStructureOptions_ShowBlockStructureGuidesForCommentsAndPreprocessorRegions", BlockStructureOptions.Default.ShowBlockStructureGuidesForCommentsAndPreprocessorRegions); public static readonly PerLanguageOption2 ShowBlockStructureGuidesForDeclarationLevelConstructs = new( - FeatureName, "ShowBlockStructureGuidesForDeclarationLevelConstructs", BlockStructureOptions.Default.ShowBlockStructureGuidesForDeclarationLevelConstructs, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ShowBlockStructureGuidesForDeclarationLevelConstructs")); + "BlockStructureOptions_ShowBlockStructureGuidesForDeclarationLevelConstructs", BlockStructureOptions.Default.ShowBlockStructureGuidesForDeclarationLevelConstructs); public static readonly PerLanguageOption2 ShowBlockStructureGuidesForCodeLevelConstructs = new( - FeatureName, "ShowBlockStructureGuidesForCodeLevelConstructs", BlockStructureOptions.Default.ShowBlockStructureGuidesForCodeLevelConstructs, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ShowBlockStructureGuidesForCodeLevelConstructs")); + "BlockStructureOptions_ShowBlockStructureGuidesForCodeLevelConstructs", BlockStructureOptions.Default.ShowBlockStructureGuidesForCodeLevelConstructs); public static readonly PerLanguageOption2 ShowOutliningForCommentsAndPreprocessorRegions = new( - FeatureName, "ShowOutliningForCommentsAndPreprocessorRegions", BlockStructureOptions.Default.ShowOutliningForCommentsAndPreprocessorRegions, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ShowOutliningForCommentsAndPreprocessorRegions")); + "BlockStructureOptions_ShowOutliningForCommentsAndPreprocessorRegions", BlockStructureOptions.Default.ShowOutliningForCommentsAndPreprocessorRegions); public static readonly PerLanguageOption2 ShowOutliningForDeclarationLevelConstructs = new( - FeatureName, "ShowOutliningForDeclarationLevelConstructs", BlockStructureOptions.Default.ShowOutliningForDeclarationLevelConstructs, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ShowOutliningForDeclarationLevelConstructs")); + "BlockStructureOptions_ShowOutliningForDeclarationLevelConstructs", BlockStructureOptions.Default.ShowOutliningForDeclarationLevelConstructs); public static readonly PerLanguageOption2 ShowOutliningForCodeLevelConstructs = new( - FeatureName, "ShowOutliningForCodeLevelConstructs", BlockStructureOptions.Default.ShowOutliningForCodeLevelConstructs, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ShowOutliningForCodeLevelConstructs")); + "BlockStructureOptions_ShowOutliningForCodeLevelConstructs", BlockStructureOptions.Default.ShowOutliningForCodeLevelConstructs); public static readonly PerLanguageOption2 CollapseRegionsWhenFirstOpened = new( - FeatureName, "CollapseRegionsWhenFirstOpened", BlockStructureOptions.Default.CollapseRegionsWhenFirstOpened, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.CollapseRegionsWhenFirstOpened")); + "BlockStructureOptions_CollapseRegionsWhenFirstOpened", BlockStructureOptions.Default.CollapseRegionsWhenFirstOpened); public static readonly PerLanguageOption2 CollapseImportsWhenFirstOpened = new( - FeatureName, "CollapseImportsWhenFirstOpened", BlockStructureOptions.Default.CollapseImportsWhenFirstOpened, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.CollapseImportsWhenFirstOpened")); + "BlockStructureOptions_CollapseImportsWhenFirstOpened", BlockStructureOptions.Default.CollapseImportsWhenFirstOpened); public static readonly PerLanguageOption2 CollapseSourceLinkEmbeddedDecompiledFilesWhenFirstOpened = new( - FeatureName, "CollapseMetadataImplementationsWhenFirstOpened", BlockStructureOptions.Default.CollapseMetadataImplementationsWhenFirstOpened, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.CollapseMetadataImplementationsWhenFirstOpened")); + "BlockStructureOptions_CollapseMetadataImplementationsWhenFirstOpened", BlockStructureOptions.Default.CollapseMetadataImplementationsWhenFirstOpened); + public static readonly PerLanguageOption2 CollapseMetadataSignatureFilesWhenFirstOpened = new( - FeatureName, "CollapseEmptyMetadataImplementationsWhenFirstOpened", BlockStructureOptions.Default.CollapseEmptyMetadataImplementationsWhenFirstOpened, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.CollapseEmptyMetadataImplementationsWhenFirstOpened")); + "BlockStructureOptions_CollapseEmptyMetadataImplementationsWhenFirstOpened", BlockStructureOptions.Default.CollapseEmptyMetadataImplementationsWhenFirstOpened); public static readonly PerLanguageOption2 CollapseRegionsWhenCollapsingToDefinitions = new( - FeatureName, "CollapseRegionsWhenCollapsingToDefinitions", BlockStructureOptions.Default.CollapseRegionsWhenCollapsingToDefinitions, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.CollapseRegionsWhenCollapsingToDefinitions")); + "BlockStructureOptions_CollapseRegionsWhenCollapsingToDefinitions", BlockStructureOptions.Default.CollapseRegionsWhenCollapsingToDefinitions); public static readonly PerLanguageOption2 MaximumBannerLength = new( - FeatureName, "MaximumBannerLength", BlockStructureOptions.Default.MaximumBannerLength, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.MaximumBannerLength")); + "BlockStructureOptions_MaximumBannerLength", BlockStructureOptions.Default.MaximumBannerLength); } diff --git a/src/Features/LanguageServer/Protocol/Features/Options/ClassificationOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/ClassificationOptionsStorage.cs index 5b2ea0e324ad9..df4e784311962 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/ClassificationOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/ClassificationOptionsStorage.cs @@ -18,14 +18,11 @@ public static ClassificationOptions GetClassificationOptions(this IGlobalOptionS }; public static PerLanguageOption2 ClassifyReassignedVariables = - new("ClassificationOptions", "ClassifyReassignedVariables", ClassificationOptions.Default.ClassifyReassignedVariables, - storageLocation: new RoamingProfileStorageLocation($"TextEditor.%LANGUAGE%.Specific.ClassificationOptions.ClassifyReassignedVariables")); + new("ClassificationOptions_ClassifyReassignedVariables", ClassificationOptions.Default.ClassifyReassignedVariables); public static PerLanguageOption2 ColorizeRegexPatterns = - new("RegularExpressionsOptions", "ColorizeRegexPatterns", ClassificationOptions.Default.ColorizeRegexPatterns, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ColorizeRegexPatterns")); + new("RegularExpressionsOptions_ColorizeRegexPatterns", ClassificationOptions.Default.ColorizeRegexPatterns); public static PerLanguageOption2 ColorizeJsonPatterns = - new("JsonFeatureOptions", "ColorizeJsonPatterns", ClassificationOptions.Default.ColorizeJsonPatterns, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ColorizeJsonPatterns")); + new("JsonFeatureOptions_ColorizeJsonPatterns", ClassificationOptions.Default.ColorizeJsonPatterns); } diff --git a/src/Features/LanguageServer/Protocol/Features/Options/CodeActionOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/CodeActionOptionsStorage.cs index 02d2ebfad5121..aabe5a9bd266f 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/CodeActionOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/CodeActionOptionsStorage.cs @@ -19,7 +19,7 @@ namespace Microsoft.CodeAnalysis.CodeActions internal static class CodeActionOptionsStorage { public static readonly PerLanguageOption2 WrappingColumn = - new("FormattingOptions", "WrappingColumn", CodeActionOptions.DefaultWrappingColumn); + new("FormattingOptions_WrappingColumn", CodeActionOptions.DefaultWrappingColumn); public static CodeActionOptions GetCodeActionOptions(this IGlobalOptionService globalOptions, LanguageServices languageServices) => new() @@ -42,8 +42,6 @@ internal static CodeActionOptionsProvider GetCodeActionOptionsProvider(this IGlo } public static readonly PerLanguageOption2 ConditionalExpressionWrappingLength = new( - "UseConditionalExpressionOptions", - "ConditionalExpressionWrappingLength", CodeActionOptions.DefaultConditionalExpressionWrappingLength, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ConditionalExpressionWrappingLength")); + "UseConditionalExpressionOptions_ConditionalExpressionWrappingLength", CodeActionOptions.DefaultConditionalExpressionWrappingLength); } } diff --git a/src/Features/LanguageServer/Protocol/Features/Options/CodeGenerationOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/CodeGenerationOptionsStorage.cs index 9922d93d63bb7..0479ee57c930c 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/CodeGenerationOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/CodeGenerationOptionsStorage.cs @@ -6,18 +6,11 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.CodeCleanup; -using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Options; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeGeneration; -internal interface ICodeGenerationOptionsStorage : ILanguageService -{ - CodeGenerationOptions GetOptions(IGlobalOptionService globalOptions); -} - internal static class CodeGenerationOptionsStorage { public static ValueTask GetCodeGenerationOptionsAsync(this Document document, IGlobalOptionService globalOptions, CancellationToken cancellationToken) @@ -26,14 +19,8 @@ public static ValueTask GetCodeGenerationOptionsAsync(thi public static ValueTask GetCleanCodeGenerationOptionsAsync(this Document document, IGlobalOptionService globalOptions, CancellationToken cancellationToken) => document.GetCleanCodeGenerationOptionsAsync(globalOptions.GetCleanCodeGenerationOptions(document.Project.Services), cancellationToken); - public static CodeGenerationOptions.CommonOptions GetCommonCodeGenerationOptions(this IGlobalOptionService globalOptions, string language) - => new() - { - NamingStyle = globalOptions.GetNamingStylePreferences(language) - }; - public static CodeGenerationOptions GetCodeGenerationOptions(this IGlobalOptionService globalOptions, LanguageServices languageServices) - => languageServices.GetRequiredService().GetOptions(globalOptions); + => languageServices.GetRequiredService().GetCodeGenerationOptions(globalOptions, fallbackOptions: null); public static CodeAndImportGenerationOptions GetCodeAndImportGenerationOptions(this IGlobalOptionService globalOptions, LanguageServices languageServices) => new() diff --git a/src/Features/LanguageServer/Protocol/Features/Options/CodeStyleOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/CodeStyleOptionsStorage.cs index 5bddc86c403d0..3f3372fd0227d 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/CodeStyleOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/CodeStyleOptionsStorage.cs @@ -2,57 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Simplification; -using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.AddImport; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeStyle; -internal interface ICodeStyleOptionsStorage : ILanguageService -{ - IdeCodeStyleOptions GetOptions(IGlobalOptionService globalOptions); -} - internal static class CodeStyleOptionsStorage { public static IdeCodeStyleOptions GetCodeStyleOptions(this IGlobalOptionService globalOptions, LanguageServices languageServices) - => languageServices.GetRequiredService().GetOptions(globalOptions); - - public static IdeCodeStyleOptions.CommonOptions GetCommonCodeStyleOptions(this IGlobalOptionService globalOptions, string language) - => new() - { - PreferObjectInitializer = globalOptions.GetOption(CodeStyleOptions2.PreferObjectInitializer, language), - PreferCollectionInitializer = globalOptions.GetOption(CodeStyleOptions2.PreferCollectionInitializer, language), - PreferSimplifiedBooleanExpressions = globalOptions.GetOption(CodeStyleOptions2.PreferSimplifiedBooleanExpressions, language), - OperatorPlacementWhenWrapping = globalOptions.GetOption(CodeStyleOptions2.OperatorPlacementWhenWrapping), - PreferCoalesceExpression = globalOptions.GetOption(CodeStyleOptions2.PreferCoalesceExpression, language), - PreferNullPropagation = globalOptions.GetOption(CodeStyleOptions2.PreferNullPropagation, language), - PreferExplicitTupleNames = globalOptions.GetOption(CodeStyleOptions2.PreferExplicitTupleNames, language), - PreferAutoProperties = globalOptions.GetOption(CodeStyleOptions2.PreferAutoProperties, language), - PreferInferredTupleNames = globalOptions.GetOption(CodeStyleOptions2.PreferInferredTupleNames, language), - PreferInferredAnonymousTypeMemberNames = globalOptions.GetOption(CodeStyleOptions2.PreferInferredAnonymousTypeMemberNames, language), - PreferIsNullCheckOverReferenceEqualityMethod = globalOptions.GetOption(CodeStyleOptions2.PreferIsNullCheckOverReferenceEqualityMethod, language), - PreferConditionalExpressionOverAssignment = globalOptions.GetOption(CodeStyleOptions2.PreferConditionalExpressionOverAssignment, language), - PreferConditionalExpressionOverReturn = globalOptions.GetOption(CodeStyleOptions2.PreferConditionalExpressionOverReturn, language), - PreferCompoundAssignment = globalOptions.GetOption(CodeStyleOptions2.PreferCompoundAssignment, language), - PreferSimplifiedInterpolation = globalOptions.GetOption(CodeStyleOptions2.PreferSimplifiedInterpolation, language), - UnusedParameters = globalOptions.GetOption(CodeStyleOptions2.UnusedParameters, language), - AccessibilityModifiersRequired = globalOptions.GetOption(CodeStyleOptions2.AccessibilityModifiersRequired, language), - PreferReadonly = globalOptions.GetOption(CodeStyleOptions2.PreferReadonly, language), - ArithmeticBinaryParentheses = globalOptions.GetOption(CodeStyleOptions2.ArithmeticBinaryParentheses, language), - OtherBinaryParentheses = globalOptions.GetOption(CodeStyleOptions2.OtherBinaryParentheses, language), - RelationalBinaryParentheses = globalOptions.GetOption(CodeStyleOptions2.RelationalBinaryParentheses, language), - OtherParentheses = globalOptions.GetOption(CodeStyleOptions2.OtherParentheses, language), - ForEachExplicitCastInSource = globalOptions.GetOption(CodeStyleOptions2.ForEachExplicitCastInSource), - PreferNamespaceAndFolderMatchStructure = globalOptions.GetOption(CodeStyleOptions2.PreferNamespaceAndFolderMatchStructure, language), - AllowMultipleBlankLines = globalOptions.GetOption(CodeStyleOptions2.AllowMultipleBlankLines, language), - AllowStatementImmediatelyAfterBlock = globalOptions.GetOption(CodeStyleOptions2.AllowStatementImmediatelyAfterBlock, language), - RemoveUnnecessarySuppressionExclusions = globalOptions.GetOption(CodeStyleOptions2.RemoveUnnecessarySuppressionExclusions) - }; + => languageServices.GetRequiredService().GetIdeCodeStyleOptions(globalOptions, fallbackOptions: null); } diff --git a/src/Features/LanguageServer/Protocol/Features/Options/CompletionOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/CompletionOptionsStorage.cs index 3788cbbeeb82b..354fbe4c1329b 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/CompletionOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/CompletionOptionsStorage.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using Microsoft.CodeAnalysis.CodeStyle; -using Microsoft.CodeAnalysis.Completion.Providers.Snippets; using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.Completion; @@ -26,7 +25,6 @@ public static CompletionOptions GetCompletionOptions(this IGlobalOptionService o ProvideDateAndTimeCompletions = options.GetOption(ProvideDateAndTimeCompletions, language), ProvideRegexCompletions = options.GetOption(ProvideRegexCompletions, language), ForceExpandedCompletionIndexCreation = options.GetOption(ForceExpandedCompletionIndexCreation), - UpdateImportCompletionCacheInBackground = options.GetOption(UpdateImportCompletionCacheInBackground), NamingStyleFallbackOptions = options.GetNamingStylePreferences(language), ShowNewSnippetExperienceUserOption = options.GetOption(ShowNewSnippetExperienceUserOption, language), ShowNewSnippetExperienceFeatureFlag = options.GetOption(ShowNewSnippetExperienceFeatureFlag) @@ -34,77 +32,29 @@ public static CompletionOptions GetCompletionOptions(this IGlobalOptionService o // feature flags - public static readonly Option2 UnnamedSymbolCompletionDisabledFeatureFlag = new(nameof(CompletionOptions), nameof(UnnamedSymbolCompletionDisabledFeatureFlag), - CompletionOptions.Default.UnnamedSymbolCompletionDisabled, - new FeatureFlagStorageLocation("Roslyn.UnnamedSymbolCompletionDisabled")); - - public static readonly Option2 ShowNewSnippetExperienceFeatureFlag = new(nameof(CompletionOptions), nameof(ShowNewSnippetExperienceFeatureFlag), - CompletionOptions.Default.ShowNewSnippetExperienceFeatureFlag, - new FeatureFlagStorageLocation("Roslyn.SnippetCompletion")); - - public static readonly PerLanguageOption2 HideAdvancedMembers = new( - "CompletionOptions", "HideAdvancedMembers", CompletionOptions.Default.HideAdvancedMembers, - new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Hide Advanced Auto List Members")); - - public static readonly PerLanguageOption2 TriggerOnTyping = new( - "CompletionOptions", "TriggerOnTyping", CompletionOptions.Default.TriggerOnTyping, - new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Auto List Members")); - - public static readonly PerLanguageOption2 TriggerOnTypingLetters = new(nameof(CompletionOptions), nameof(TriggerOnTypingLetters), CompletionOptions.Default.TriggerOnTypingLetters, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.TriggerOnTypingLetters")); - - public static readonly PerLanguageOption2 TriggerOnDeletion = new(nameof(CompletionOptions), nameof(TriggerOnDeletion), CompletionOptions.Default.TriggerOnDeletion, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.TriggerOnDeletion")); - - public static readonly PerLanguageOption2 EnterKeyBehavior = - new(nameof(CompletionOptions), nameof(EnterKeyBehavior), CompletionOptions.Default.EnterKeyBehavior, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.EnterKeyBehavior")); - - public static readonly PerLanguageOption2 SnippetsBehavior = - new(nameof(CompletionOptions), nameof(SnippetsBehavior), CompletionOptions.Default.SnippetsBehavior, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.SnippetsBehavior")); - - public static readonly PerLanguageOption2 ShowNameSuggestions = - new(nameof(CompletionOptions), nameof(ShowNameSuggestions), CompletionOptions.Default.ShowNameSuggestions, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ShowNameSuggestions")); + public static readonly Option2 UnnamedSymbolCompletionDisabledFeatureFlag = new("CompletionOptions_UnnamedSymbolCompletionDisabledFeatureFlag", CompletionOptions.Default.UnnamedSymbolCompletionDisabled); + public static readonly Option2 ShowNewSnippetExperienceFeatureFlag = new("CompletionOptions_ShowNewSnippetExperienceFeatureFlag", CompletionOptions.Default.ShowNewSnippetExperienceFeatureFlag); + public static readonly PerLanguageOption2 HideAdvancedMembers = new("CompletionOptions_HideAdvancedMembers", CompletionOptions.Default.HideAdvancedMembers); + public static readonly PerLanguageOption2 TriggerOnTyping = new("CompletionOptions_TriggerOnTyping", CompletionOptions.Default.TriggerOnTyping); + public static readonly PerLanguageOption2 TriggerOnTypingLetters = new("CompletionOptions_TriggerOnTypingLetters", CompletionOptions.Default.TriggerOnTypingLetters); + public static readonly PerLanguageOption2 TriggerOnDeletion = new("CompletionOptions_TriggerOnDeletion", CompletionOptions.Default.TriggerOnDeletion); + public static readonly PerLanguageOption2 EnterKeyBehavior = new("CompletionOptions_EnterKeyBehavior", CompletionOptions.Default.EnterKeyBehavior); + public static readonly PerLanguageOption2 SnippetsBehavior = new("CompletionOptions_SnippetsBehavior", CompletionOptions.Default.SnippetsBehavior); + public static readonly PerLanguageOption2 ShowNameSuggestions = new("CompletionOptions_ShowNameSuggestions", CompletionOptions.Default.ShowNameSuggestions); //Dev16 options // Use tri-value so the default state can be used to turn on the feature with experimentation service. - public static readonly PerLanguageOption2 ShowItemsFromUnimportedNamespaces = - new(nameof(CompletionOptions), nameof(ShowItemsFromUnimportedNamespaces), CompletionOptions.Default.ShowItemsFromUnimportedNamespaces, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ShowItemsFromUnimportedNamespaces")); + public static readonly PerLanguageOption2 ShowItemsFromUnimportedNamespaces = new("CompletionOptions_ShowItemsFromUnimportedNamespaces", CompletionOptions.Default.ShowItemsFromUnimportedNamespaces); - public static readonly PerLanguageOption2 TriggerInArgumentLists = - new(nameof(CompletionOptions), nameof(TriggerInArgumentLists), CompletionOptions.Default.TriggerInArgumentLists, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.TriggerInArgumentLists")); + public static readonly PerLanguageOption2 TriggerInArgumentLists = new("CompletionOptions_TriggerInArgumentLists", CompletionOptions.Default.TriggerInArgumentLists); // Test-only option - public static readonly Option2 ForceExpandedCompletionIndexCreation - = new(nameof(CompletionOptions), nameof(ForceExpandedCompletionIndexCreation), defaultValue: false); - - // Set to true to update import completion cache in background if the provider isn't supposed to be triggered in the context. - // (cache will alsways be refreshed when provider is triggered) - public static readonly Option2 UpdateImportCompletionCacheInBackground - = new(nameof(CompletionOptions), nameof(UpdateImportCompletionCacheInBackground), defaultValue: false); + public static readonly Option2 ForceExpandedCompletionIndexCreation = new("CompletionOptions_ForceExpandedCompletionIndexCreation", defaultValue: false); // Embedded languages: - public static PerLanguageOption2 ProvideRegexCompletions = - new( - "RegularExpressionsOptions", - nameof(ProvideRegexCompletions), - CompletionOptions.Default.ProvideRegexCompletions, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ProvideRegexCompletions")); - - public static readonly PerLanguageOption2 ProvideDateAndTimeCompletions = - new( - "DateAndTime", - nameof(ProvideDateAndTimeCompletions), - CompletionOptions.Default.ProvideDateAndTimeCompletions, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ProvideDateAndTimeCompletions")); - - public static readonly PerLanguageOption2 ShowNewSnippetExperienceUserOption - = new(nameof(CompletionOptions), nameof(ShowNewSnippetExperienceUserOption), CompletionOptions.Default.ShowNewSnippetExperienceUserOption, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ShowNewSnippetExperience")); + public static PerLanguageOption2 ProvideRegexCompletions = new("RegularExpressionsOptions_ProvideRegexCompletions", CompletionOptions.Default.ProvideRegexCompletions); + public static readonly PerLanguageOption2 ProvideDateAndTimeCompletions = new("DateAndTime_ProvideDateAndTimeCompletions", CompletionOptions.Default.ProvideDateAndTimeCompletions); + public static readonly PerLanguageOption2 ShowNewSnippetExperienceUserOption = new("CompletionOptions_ShowNewSnippetExperienceUserOption", CompletionOptions.Default.ShowNewSnippetExperienceUserOption); } diff --git a/src/Features/LanguageServer/Protocol/Features/Options/DiagnosticOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/DiagnosticOptionsStorage.cs index 506fbce515ed9..f8a1f89fbc4fe 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/DiagnosticOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/DiagnosticOptionsStorage.cs @@ -2,25 +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.Collections.Immutable; -using System.Composition; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Options.Providers; namespace Microsoft.CodeAnalysis.Diagnostics { internal sealed class DiagnosticOptionsStorage { - private const string FeatureName = "DiagnosticOptions"; - public static readonly Option2 LspPullDiagnosticsFeatureFlag = new( - FeatureName, nameof(LspPullDiagnosticsFeatureFlag), defaultValue: false, - new FeatureFlagStorageLocation("Lsp.PullDiagnostics")); + "DiagnosticOptions_LspPullDiagnosticsFeatureFlag", defaultValue: false); public static readonly Option2 LogTelemetryForBackgroundAnalyzerExecution = new( - FeatureName, nameof(LogTelemetryForBackgroundAnalyzerExecution), defaultValue: false, - new FeatureFlagStorageLocation($"Roslyn.LogTelemetryForBackgroundAnalyzerExecution")); + "DiagnosticOptions_LogTelemetryForBackgroundAnalyzerExecution", defaultValue: false); } } diff --git a/src/Features/LanguageServer/Protocol/Features/Options/DocumentationCommentOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/DocumentationCommentOptionsStorage.cs index b8596c9b3ebeb..c2ea26422a590 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/DocumentationCommentOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/DocumentationCommentOptionsStorage.cs @@ -20,7 +20,6 @@ public static DocumentationCommentOptions GetDocumentationCommentOptions(this IG }; public static readonly PerLanguageOption2 AutoXmlDocCommentGeneration = new( - "DocumentationCommentOptions", "AutoXmlDocCommentGeneration", DocumentationCommentOptions.Default.AutoXmlDocCommentGeneration, - storageLocation: new RoamingProfileStorageLocation(language => language == LanguageNames.VisualBasic ? "TextEditor.%LANGUAGE%.Specific.AutoComment" : "TextEditor.%LANGUAGE%.Specific.Automatic XML Doc Comment Generation")); + "DocumentationCommentOptions_AutoXmlDocCommentGeneration", DocumentationCommentOptions.Default.AutoXmlDocCommentGeneration); } diff --git a/src/Features/LanguageServer/Protocol/Features/Options/ExtractMethodOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/ExtractMethodOptionsStorage.cs index f5a7955c5a4fc..ff349b010fcad 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/ExtractMethodOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/ExtractMethodOptionsStorage.cs @@ -34,6 +34,5 @@ public static ValueTask GetExtractMethodGenerati => document.GetExtractMethodGenerationOptionsAsync(globalOptions.GetExtractMethodGenerationOptions(document.Project.Services), cancellationToken); public static readonly PerLanguageOption2 DontPutOutOrRefOnStruct = new( - "ExtractMethodOptions", "DontPutOutOrRefOnStruct", ExtractMethodOptions.Default.DontPutOutOrRefOnStruct, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.Don't Put Out Or Ref On Strcut")); // NOTE: the spelling error is what we've shipped and thus should not change + "ExtractMethodOptions_DontPutOutOrRefOnStruct", ExtractMethodOptions.Default.DontPutOutOrRefOnStruct); // NOTE: the spelling error is what we've shipped and thus should not change } diff --git a/src/Features/LanguageServer/Protocol/Features/Options/FeatureFlagStorageLocation.cs b/src/Features/LanguageServer/Protocol/Features/Options/FeatureFlagStorageLocation.cs deleted file mode 100644 index bfe7f7497e687..0000000000000 --- a/src/Features/LanguageServer/Protocol/Features/Options/FeatureFlagStorageLocation.cs +++ /dev/null @@ -1,23 +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 Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.Options -{ - /// - /// Specifies that the option is stored in feature flag storage. - /// - internal sealed class FeatureFlagStorageLocation : OptionStorageLocation2 - { - public string Name { get; } - - public FeatureFlagStorageLocation(string name) - { - // feature flag name must be qualified by a component name, e.g. "Roslyn.", "Xaml.", "Lsp.", etc. - Contract.ThrowIfFalse(name.IndexOf('.') > 0); - Name = name; - } - } -} diff --git a/src/Features/LanguageServer/Protocol/Features/Options/HighlightingOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/HighlightingOptionsStorage.cs index 1f8f5284e2955..acdb921e17ffc 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/HighlightingOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/HighlightingOptionsStorage.cs @@ -16,14 +16,10 @@ public static HighlightingOptions GetHighlightingOptions(this IGlobalOptionServi }; public static PerLanguageOption2 HighlightRelatedRegexComponentsUnderCursor = - new("RegularExpressionsOptions", - "HighlightRelatedRegexComponentsUnderCursor", - defaultValue: true, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.HighlightRelatedRegexComponentsUnderCursor")); + new("RegularExpressionsOptions_HighlightRelatedRegexComponentsUnderCursor", + defaultValue: true); public static PerLanguageOption2 HighlightRelatedJsonComponentsUnderCursor = - new("JsonFeatureOptions", - "HighlightRelatedJsonComponentsUnderCursor", - defaultValue: HighlightingOptions.Default.HighlightRelatedJsonComponentsUnderCursor, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.HighlightRelatedJsonComponentsUnderCursor")); + new("JsonFeatureOptions_HighlightRelatedJsonComponentsUnderCursor", + defaultValue: HighlightingOptions.Default.HighlightRelatedJsonComponentsUnderCursor); } diff --git a/src/Features/LanguageServer/Protocol/Features/Options/IdeAnalyzerOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/IdeAnalyzerOptionsStorage.cs index cbda788e10eb9..7bcef98e8662c 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/IdeAnalyzerOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/IdeAnalyzerOptionsStorage.cs @@ -2,13 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Simplification; -using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.CodeCleanup; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.CodeGeneration; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.Diagnostics; @@ -20,7 +18,9 @@ public static IdeAnalyzerOptions GetIdeAnalyzerOptions(this IGlobalOptionService public static IdeAnalyzerOptions GetIdeAnalyzerOptions(this IGlobalOptionService globalOptions, LanguageServices languageServices) { var language = languageServices.Language; - var supportsLanguageSpecificOptions = languageServices.GetService() != null; + + // avoid throwing for languages other than C# and VB: + var supportsLanguageSpecificOptions = languageServices.GetService() != null; return new() { @@ -36,30 +36,17 @@ public static IdeAnalyzerOptions GetIdeAnalyzerOptions(this IGlobalOptionService } public static readonly Option2 CrashOnAnalyzerException = new( - "InternalDiagnosticsOptions", "CrashOnAnalyzerException", IdeAnalyzerOptions.CommonDefault.CrashOnAnalyzerException, - storageLocation: new LocalUserProfileStorageLocation(@"Roslyn\Internal\Diagnostics\CrashOnAnalyzerException")); + "InternalDiagnosticsOptions_CrashOnAnalyzerException", IdeAnalyzerOptions.CommonDefault.CrashOnAnalyzerException); - public static PerLanguageOption2 ReportInvalidPlaceholdersInStringDotFormatCalls = - new("ValidateFormatStringOption", - "ReportInvalidPlaceholdersInStringDotFormatCalls", - IdeAnalyzerOptions.CommonDefault.ReportInvalidPlaceholdersInStringDotFormatCalls, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.WarnOnInvalidStringDotFormatCalls")); + public static PerLanguageOption2 ReportInvalidPlaceholdersInStringDotFormatCalls = new( + "ValidateFormatStringOption_ReportInvalidPlaceholdersInStringDotFormatCalls", IdeAnalyzerOptions.CommonDefault.ReportInvalidPlaceholdersInStringDotFormatCalls); - public static PerLanguageOption2 ReportInvalidRegexPatterns = - new("RegularExpressionsOptions", - "ReportInvalidRegexPatterns", - IdeAnalyzerOptions.CommonDefault.ReportInvalidRegexPatterns, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ReportInvalidRegexPatterns")); + public static PerLanguageOption2 ReportInvalidRegexPatterns = new( + "RegularExpressionsOptions_ReportInvalidRegexPatterns", IdeAnalyzerOptions.CommonDefault.ReportInvalidRegexPatterns); - public static PerLanguageOption2 ReportInvalidJsonPatterns = - new("JsonFeatureOptions", - "ReportInvalidJsonPatterns", - defaultValue: IdeAnalyzerOptions.CommonDefault.ReportInvalidJsonPatterns, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ReportInvalidJsonPatterns")); + public static PerLanguageOption2 ReportInvalidJsonPatterns = new( + "JsonFeatureOptions_ReportInvalidJsonPatterns", IdeAnalyzerOptions.CommonDefault.ReportInvalidJsonPatterns); - public static PerLanguageOption2 DetectAndOfferEditorFeaturesForProbableJsonStrings = - new("JsonFeatureOptions", - "DetectAndOfferEditorFeaturesForProbableJsonStrings", - defaultValue: IdeAnalyzerOptions.CommonDefault.DetectAndOfferEditorFeaturesForProbableJsonStrings, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.DetectAndOfferEditorFeaturesForProbableJsonStrings")); + public static PerLanguageOption2 DetectAndOfferEditorFeaturesForProbableJsonStrings = new( + "JsonFeatureOptions_DetectAndOfferEditorFeaturesForProbableJsonStrings", IdeAnalyzerOptions.CommonDefault.DetectAndOfferEditorFeaturesForProbableJsonStrings); } diff --git a/src/Features/LanguageServer/Protocol/Features/Options/ImplementTypeOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/ImplementTypeOptionsStorage.cs index 7aebf1fd2fc51..fe89a027977f5 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/ImplementTypeOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/ImplementTypeOptionsStorage.cs @@ -21,18 +21,12 @@ public static ImplementTypeGenerationOptions GetImplementTypeGenerationOptions(t => new(globalOptions.GetImplementTypeOptions(languageServices.Language), globalOptions.CreateProvider()); - private const string FeatureName = "ImplementTypeOptions"; - public static readonly PerLanguageOption2 InsertionBehavior = - new(FeatureName, - "InsertionBehavior", - defaultValue: ImplementTypeOptions.Default.InsertionBehavior, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.ImplementTypeOptions.InsertionBehavior")); + new("ImplementTypeOptions_InsertionBehavior", + defaultValue: ImplementTypeOptions.Default.InsertionBehavior); public static readonly PerLanguageOption2 PropertyGenerationBehavior = - new(FeatureName, - "PropertyGenerationBehavior", - defaultValue: ImplementTypeOptions.Default.PropertyGenerationBehavior, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.ImplementTypeOptions.PropertyGenerationBehavior")); + new("ImplementTypeOptions_PropertyGenerationBehavior", + defaultValue: ImplementTypeOptions.Default.PropertyGenerationBehavior); } } diff --git a/src/Features/LanguageServer/Protocol/Features/Options/InternalDiagnosticsOptions.cs b/src/Features/LanguageServer/Protocol/Features/Options/InternalDiagnosticsOptions.cs index 2be5ca07a6cf4..b541859463ba0 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/InternalDiagnosticsOptions.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/InternalDiagnosticsOptions.cs @@ -8,6 +8,20 @@ namespace Microsoft.CodeAnalysis.Diagnostics; internal static class InternalDiagnosticsOptions { - public static readonly Option2 NormalDiagnosticMode = new("InternalDiagnosticsOptions", "NormalDiagnosticMode", defaultValue: DiagnosticMode.Default, - storageLocation: new LocalUserProfileStorageLocation(@"Roslyn\Internal\Diagnostics\NormalDiagnosticMode")); + /// + /// Diagnostic mode setting for Razor. This should always be as there is no push support in Razor. + /// This option is only for passing to the diagnostics service and can be removed when we switch all of Roslyn to LSP pull. + /// + public static readonly Option2 RazorDiagnosticMode = new( + "InternalDiagnosticsOptions_RazorDiagnosticMode", defaultValue: DiagnosticMode.LspPull); + + /// + /// Diagnostic mode setting for Live Share. This should always be as there is no push support in Live Share. + /// This option is only for passing to the diagnostics service and can be removed when we switch all of Roslyn to LSP pull. + /// + public static readonly Option2 LiveShareDiagnosticMode = new( + "InternalDiagnosticsOptions_LiveShareDiagnosticMode", defaultValue: DiagnosticMode.LspPull); + + public static readonly Option2 NormalDiagnosticMode = new( + "InternalDiagnosticsOptions_NormalDiagnosticMode", defaultValue: DiagnosticMode.Default); } diff --git a/src/Features/LanguageServer/Protocol/Features/Options/MetadataAsSourceOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/MetadataAsSourceOptionsStorage.cs index 24125b6566d9a..03e60a1f6c066 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/MetadataAsSourceOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/MetadataAsSourceOptionsStorage.cs @@ -2,11 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Simplification; namespace Microsoft.CodeAnalysis.MetadataAsSource; @@ -20,15 +18,7 @@ public static MetadataAsSourceOptions GetMetadataAsSourceOptions(this IGlobalOpt NavigateToSourceLinkAndEmbeddedSources = globalOptions.GetOption(NavigateToSourceLinkAndEmbeddedSources), }; - public static Option2 NavigateToDecompiledSources = - new("FeatureOnOffOptions", "NavigateToDecompiledSources", defaultValue: true, - storageLocation: new RoamingProfileStorageLocation($"TextEditor.NavigateToDecompiledSources")); - - public static Option2 AlwaysUseDefaultSymbolServers = - new("FeatureOnOffOptions", "AlwaysUseDefaultSymbolServers", defaultValue: true, - storageLocation: new RoamingProfileStorageLocation($"TextEditor.AlwaysUseDefaultSymbolServers")); - - public static Option2 NavigateToSourceLinkAndEmbeddedSources = - new("FeatureOnOffOptions", "NavigateToSourceLinkAndEmbeddedSources", defaultValue: true, - storageLocation: new RoamingProfileStorageLocation($"TextEditor.NavigateToSourceLinkAndEmbeddedSources")); + public static Option2 NavigateToDecompiledSources = new("FeatureOnOffOptions_NavigateToDecompiledSources", defaultValue: true); + public static Option2 AlwaysUseDefaultSymbolServers = new("FeatureOnOffOptions_AlwaysUseDefaultSymbolServers", defaultValue: true); + public static Option2 NavigateToSourceLinkAndEmbeddedSources = new("FeatureOnOffOptions_NavigateToSourceLinkAndEmbeddedSources", defaultValue: true); } diff --git a/src/Features/LanguageServer/Protocol/Features/Options/QuickInfoOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/QuickInfoOptionsStorage.cs index 7dc83fc753593..122487ac63035 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/QuickInfoOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/QuickInfoOptionsStorage.cs @@ -8,21 +8,17 @@ namespace Microsoft.CodeAnalysis.QuickInfo { internal static class QuickInfoOptionsStorage { - public static QuickInfoOptions GetQuickInfoOptions(this IGlobalOptionService globalOptions, string? language) + public static QuickInfoOptions GetQuickInfoOptions(this IGlobalOptionService globalOptions, string language) => new() { ShowRemarksInQuickInfo = globalOptions.GetOption(ShowRemarksInQuickInfo, language), IncludeNavigationHintsInQuickInfo = globalOptions.GetOption(IncludeNavigationHintsInQuickInfo), }; - private const string FeatureName = "QuickInfoOptions"; - public static readonly PerLanguageOption2 ShowRemarksInQuickInfo = new( - FeatureName, "ShowRemarksInQuickInfo", QuickInfoOptions.Default.ShowRemarksInQuickInfo, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ShowRemarks")); + "QuickInfoOptions_ShowRemarksInQuickInfo", QuickInfoOptions.Default.ShowRemarksInQuickInfo); public static readonly Option2 IncludeNavigationHintsInQuickInfo = new( - FeatureName, "IncludeNavigationHintsInQuickInfo", QuickInfoOptions.Default.IncludeNavigationHintsInQuickInfo, - storageLocation: new RoamingProfileStorageLocation("TextEditor.Specific.IncludeNavigationHintsInQuickInfo")); + "QuickInfoOptions_IncludeNavigationHintsInQuickInfo", QuickInfoOptions.Default.IncludeNavigationHintsInQuickInfo); } } diff --git a/src/Features/LanguageServer/Protocol/Features/Options/RazorLineFormattingOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/RazorLineFormattingOptionsStorage.cs index 0c1df2d99dc44..b24e402265e6f 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/RazorLineFormattingOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/RazorLineFormattingOptionsStorage.cs @@ -2,9 +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.Text; using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.Formatting; @@ -15,8 +12,8 @@ namespace Microsoft.CodeAnalysis.Formatting; internal static class RazorLineFormattingOptionsStorage { internal static readonly Option2 UseTabs = new( - "RazorDesignTimeDocumentFormattingOptions", "UseTabs", LineFormattingOptions.Default.UseTabs); + "RazorDesignTimeDocumentFormattingOptions_UseTabs", LineFormattingOptions.Default.UseTabs); internal static readonly Option2 TabSize = new( - "RazorDesignTimeDocumentFormattingOptions", "TabSize", LineFormattingOptions.Default.TabSize); + "RazorDesignTimeDocumentFormattingOptions_TabSize", LineFormattingOptions.Default.TabSize); } diff --git a/src/Features/LanguageServer/Protocol/Features/Options/SimplifierOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/SimplifierOptionsStorage.cs index 2ccf516cc379e..eb6542102abfb 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/SimplifierOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/SimplifierOptionsStorage.cs @@ -4,33 +4,16 @@ using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.Simplification; -internal interface ISimplifierOptionsStorage : ILanguageService -{ - SimplifierOptions GetOptions(IGlobalOptionService globalOptions); -} - internal static class SimplifierOptionsStorage { public static ValueTask GetSimplifierOptionsAsync(this Document document, IGlobalOptionService globalOptions, CancellationToken cancellationToken) => document.GetSimplifierOptionsAsync(globalOptions.GetSimplifierOptions(document.Project.Services), cancellationToken); public static SimplifierOptions GetSimplifierOptions(this IGlobalOptionService globalOptions, LanguageServices languageServices) - => languageServices.GetRequiredService().GetOptions(globalOptions); - - public static SimplifierOptions.CommonOptions GetCommonSimplifierOptions(this IGlobalOptionService globalOptions, string language) - => new() - { - QualifyFieldAccess = globalOptions.GetOption(CodeStyleOptions2.QualifyFieldAccess, language), - QualifyPropertyAccess = globalOptions.GetOption(CodeStyleOptions2.QualifyPropertyAccess, language), - QualifyMethodAccess = globalOptions.GetOption(CodeStyleOptions2.QualifyMethodAccess, language), - QualifyEventAccess = globalOptions.GetOption(CodeStyleOptions2.QualifyEventAccess, language), - PreferPredefinedTypeKeywordInMemberAccess = globalOptions.GetOption(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInMemberAccess, language), - PreferPredefinedTypeKeywordInDeclaration = globalOptions.GetOption(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration, language) - }; + => languageServices.GetRequiredService().GetSimplifierOptions(globalOptions, fallbackOptions: null); } diff --git a/src/Features/LanguageServer/Protocol/Features/Options/SolutionCrawlerOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/SolutionCrawlerOptionsStorage.cs index 659d2cbefe4e3..820486b07793f 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/SolutionCrawlerOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/SolutionCrawlerOptionsStorage.cs @@ -14,33 +14,28 @@ internal static class SolutionCrawlerOptionsStorage /// Option to turn configure background analysis scope for the current user. /// public static readonly PerLanguageOption2 BackgroundAnalysisScopeOption = new( - "SolutionCrawlerOptionsStorage", "BackgroundAnalysisScopeOption", defaultValue: BackgroundAnalysisScope.Default, - storageLocation: new RoamingProfileStorageLocation($"TextEditor.%LANGUAGE%.Specific.BackgroundAnalysisScopeOption")); + "SolutionCrawlerOptionsStorage_BackgroundAnalysisScopeOption", defaultValue: BackgroundAnalysisScope.Default); /// /// Option to turn configure background analysis scope for the current solution. /// public static readonly Option2 SolutionBackgroundAnalysisScopeOption = new( - "SolutionCrawlerOptionsStorage", "SolutionBackgroundAnalysisScopeOption", defaultValue: null); + "SolutionCrawlerOptionsStorage_SolutionBackgroundAnalysisScopeOption", defaultValue: null); /// /// Option to configure compiler diagnostics scope for the current user. /// public static readonly PerLanguageOption2 CompilerDiagnosticsScopeOption = new( - "SolutionCrawlerOptionsStorage", "CompilerDiagnosticsScopeOption", defaultValue: CompilerDiagnosticsScope.OpenFiles, - storageLocation: new RoamingProfileStorageLocation($"TextEditor.%LANGUAGE%.Specific.CompilerDiagnosticsScopeOption")); + "SolutionCrawlerOptionsStorage_CompilerDiagnosticsScopeOption", defaultValue: CompilerDiagnosticsScope.OpenFiles); public static readonly PerLanguageOption2 RemoveDocumentDiagnosticsOnDocumentClose = new( - "ServiceFeatureOnOffOptions", "RemoveDocumentDiagnosticsOnDocumentClose", defaultValue: false, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.RemoveDocumentDiagnosticsOnDocumentClose")); + "ServiceFeatureOnOffOptions_RemoveDocumentDiagnosticsOnDocumentClose", defaultValue: false); public static readonly Option2 EnableDiagnosticsInSourceGeneratedFiles = new( - "WorkspaceConfigurationOptions", "EnableDiagnosticsInSourceGeneratedFiles", defaultValue: null, - new RoamingProfileStorageLocation("TextEditor.Roslyn.Specific.EnableDiagnosticsInSourceGeneratedFilesExperiment")); + "WorkspaceConfigurationOptions_EnableDiagnosticsInSourceGeneratedFiles", defaultValue: null); public static readonly Option2 EnableDiagnosticsInSourceGeneratedFilesFeatureFlag = new( - "WorkspaceConfigurationOptions", "EnableDiagnosticsInSourceGeneratedFilesFeatureFlag", defaultValue: false, - new FeatureFlagStorageLocation("Roslyn.EnableDiagnosticsInSourceGeneratedFiles")); + "WorkspaceConfigurationOptions_EnableDiagnosticsInSourceGeneratedFilesFeatureFlag", defaultValue: false); /// /// Enables forced scope when low VM is detected to improve performance. diff --git a/src/Features/LanguageServer/Protocol/Features/Options/SymbolSearchOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/SymbolSearchOptionsStorage.cs index 63e76785a6abe..b79ff1cc01eed 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/SymbolSearchOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/SymbolSearchOptionsStorage.cs @@ -15,14 +15,10 @@ internal static SymbolSearchOptions GetSymbolSearchOptions(this IGlobalOptionSer SearchNuGetPackages = globalOptions.GetOption(SearchNuGetPackages, language) }; - private const string FeatureName = "SymbolSearchOptions"; - public static PerLanguageOption2 SearchReferenceAssemblies = - new(FeatureName, "SuggestForTypesInReferenceAssemblies", SymbolSearchOptions.Default.SearchReferenceAssemblies, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.SuggestForTypesInReferenceAssemblies")); + new("SymbolSearchOptions_SuggestForTypesInReferenceAssemblies", SymbolSearchOptions.Default.SearchReferenceAssemblies); public static PerLanguageOption2 SearchNuGetPackages = - new(FeatureName, "SuggestForTypesInNuGetPackages", SymbolSearchOptions.Default.SearchNuGetPackages, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.SuggestForTypesInNuGetPackages")); + new("SymbolSearchOptions_SuggestForTypesInNuGetPackages", SymbolSearchOptions.Default.SearchNuGetPackages); } } diff --git a/src/Features/LanguageServer/Protocol/Features/Options/SyntaxFormattingOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/SyntaxFormattingOptionsStorage.cs index 0a3d609a1edf4..cbfc056e263a2 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/SyntaxFormattingOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/SyntaxFormattingOptionsStorage.cs @@ -2,37 +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.Collections.Generic; -using System.Text; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeStyle; -using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.Formatting; -internal interface ISyntaxFormattingOptionsStorage : ILanguageService -{ - SyntaxFormattingOptions GetOptions(IGlobalOptionService globalOptions); -} - internal static class SyntaxFormattingOptionsStorage { - public static SyntaxFormattingOptions.CommonOptions GetCommonSyntaxFormattingOptions(this IGlobalOptionService globalOptions, string language) - => new() - { - LineFormatting = globalOptions.GetLineFormattingOptions(language), - SeparateImportDirectiveGroups = globalOptions.GetOption(GenerationOptions.SeparateImportDirectiveGroups, language), - AccessibilityModifiersRequired = globalOptions.GetOption(CodeStyleOptions2.AccessibilityModifiersRequired, language).Value - }; - public static ValueTask GetSyntaxFormattingOptionsAsync(this Document document, IGlobalOptionService globalOptions, CancellationToken cancellationToken) => document.GetSyntaxFormattingOptionsAsync(globalOptions.GetSyntaxFormattingOptions(document.Project.Services), cancellationToken); public static SyntaxFormattingOptions GetSyntaxFormattingOptions(this IGlobalOptionService globalOptions, LanguageServices languageServices) - => languageServices.GetRequiredService().GetOptions(globalOptions); + => languageServices.GetRequiredService().GetFormattingOptions(globalOptions, fallbackOptions: null); } diff --git a/src/Features/LanguageServer/Protocol/Features/Options/WorkspaceConfigurationOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/WorkspaceConfigurationOptionsStorage.cs index fc2a7b87d3191..e6652bdb2c198 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/WorkspaceConfigurationOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/WorkspaceConfigurationOptionsStorage.cs @@ -14,37 +14,32 @@ public static WorkspaceConfigurationOptions GetWorkspaceConfigurationOptions(thi CacheStorage: globalOptions.GetOption(CloudCacheFeatureFlag) ? StorageDatabase.CloudCache : globalOptions.GetOption(Database), EnableOpeningSourceGeneratedFiles: globalOptions.GetOption(EnableOpeningSourceGeneratedFilesInWorkspace) ?? globalOptions.GetOption(EnableOpeningSourceGeneratedFilesInWorkspaceFeatureFlag), - DisableCloneWhenProducingSkeletonReferences: globalOptions.GetOption(DisableCloneWhenProducingSkeletonReferences)); + DisableReferenceManagerRecoverableMetadata: globalOptions.GetOption(DisableReferenceManagerRecoverableMetadata), + DisableBackgroundCompilation: globalOptions.GetOption(DisableBackgroundCompilation), + DisableSharedSyntaxTrees: globalOptions.GetOption(DisableSharedSyntaxTrees)); public static readonly Option2 Database = new( - "FeatureManager/Storage", nameof(Database), WorkspaceConfigurationOptions.Default.CacheStorage, - new LocalUserProfileStorageLocation(@"Roslyn\Internal\OnOff\Features\Database")); + "Storage_Database", WorkspaceConfigurationOptions.Default.CacheStorage); public static readonly Option2 CloudCacheFeatureFlag = new( - "FeatureManager/Storage", "CloudCacheFeatureFlag", WorkspaceConfigurationOptions.Default.CacheStorage == StorageDatabase.CloudCache, - new FeatureFlagStorageLocation("Roslyn.CloudCache3")); - - public static readonly Option2 DisableCloneWhenProducingSkeletonReferences = new( - "WorkspaceConfigurationOptions", "DisableCloneWhenProducingSkeletonReferences", WorkspaceConfigurationOptions.Default.DisableCloneWhenProducingSkeletonReferences, - new FeatureFlagStorageLocation("Roslyn.DisableCloneWhenProducingSkeletonReferences")); + "Storage_CloudCacheFeatureFlag", WorkspaceConfigurationOptions.Default.CacheStorage == StorageDatabase.CloudCache); public static readonly Option2 DisableReferenceManagerRecoverableMetadata = new( - "WorkspaceConfigurationOptions", "DisableReferenceManagerRecoverableMetadata", WorkspaceConfigurationOptions.Default.DisableReferenceManagerRecoverableMetadata, - new FeatureFlagStorageLocation("Roslyn.DisableReferenceManagerRecoverableMetadata")); + "WorkspaceConfigurationOptions_DisableReferenceManagerRecoverableMetadata", WorkspaceConfigurationOptions.Default.DisableReferenceManagerRecoverableMetadata); public static readonly Option2 DisableBackgroundCompilation = new( - "WorkspaceConfigurationOptions", "DisableBackgroundCompilation", WorkspaceConfigurationOptions.Default.DisableBackgroundCompilation, - new FeatureFlagStorageLocation("Roslyn.DisableBackgroundCompilation")); + "WorkspaceConfigurationOptions_DisableBackgroundCompilation", WorkspaceConfigurationOptions.Default.DisableBackgroundCompilation); + + public static readonly Option2 DisableSharedSyntaxTrees = new( + "WorkspaceConfigurationOptions_DisableSharedSyntaxTrees", WorkspaceConfigurationOptions.Default.DisableSharedSyntaxTrees); /// /// This option allows the user to enable this. We are putting this behind a feature flag for now since we could have extensions /// surprised by this and we want some time to work through those issues. /// public static readonly Option2 EnableOpeningSourceGeneratedFilesInWorkspace = new( - "WorkspaceConfigurationOptions", "EnableOpeningSourceGeneratedFilesInWorkspace", defaultValue: null, - new RoamingProfileStorageLocation("TextEditor.Roslyn.Specific.EnableOpeningSourceGeneratedFilesInWorkspaceExperiment")); + "WorkspaceConfigurationOptions_EnableOpeningSourceGeneratedFilesInWorkspace", defaultValue: null); public static readonly Option2 EnableOpeningSourceGeneratedFilesInWorkspaceFeatureFlag = new( - "WorkspaceConfigurationOptions", "EnableOpeningSourceGeneratedFilesInWorkspaceFeatureFlag", WorkspaceConfigurationOptions.Default.EnableOpeningSourceGeneratedFiles, - new FeatureFlagStorageLocation("Roslyn.SourceGeneratorsEnableOpeningInWorkspace")); + "WorkspaceConfigurationOptions_EnableOpeningSourceGeneratedFilesInWorkspaceFeatureFlag", WorkspaceConfigurationOptions.Default.EnableOpeningSourceGeneratedFiles); } diff --git a/src/Features/LanguageServer/Protocol/Features/Options/WorkspaceConfigurationService.cs b/src/Features/LanguageServer/Protocol/Features/Options/WorkspaceConfigurationService.cs index e42b269ae1d35..3b6ffa92508a1 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/WorkspaceConfigurationService.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/WorkspaceConfigurationService.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.Host; -[ExportWorkspaceService(typeof(IWorkspaceConfigurationService)), Shared] +[ExportWorkspaceService(typeof(IWorkspaceConfigurationService), ServiceLayer.Host), Shared] internal sealed class WorkspaceConfigurationService : IWorkspaceConfigurationService { private readonly IGlobalOptionService _globalOptions; diff --git a/src/Features/LanguageServer/Protocol/Features/TaskList/TaskListOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/TaskList/TaskListOptionsStorage.cs index e82bfc0fe2742..0633d02995936 100644 --- a/src/Features/LanguageServer/Protocol/Features/TaskList/TaskListOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/TaskList/TaskListOptionsStorage.cs @@ -9,17 +9,8 @@ namespace Microsoft.CodeAnalysis.TaskList { internal static class TaskListOptionsStorage { - public static readonly Option2> Descriptors = new( - "TaskListOptionsStorage", - "Descriptors", - TaskListOptions.Default.Descriptors, - new RoamingProfileStorageLocation("Microsoft.VisualStudio.ErrorListPkg.Shims.TaskListOptions.CommentTokens")); - - public static readonly Option2 ComputeTaskListItemsForClosedFiles = new( - "TaskListOptionsStorage", - "ComputeTaskListItemsForClosedFiles", - defaultValue: true, - new RoamingProfileStorageLocation($"TextEditor.Specific.ComputeTaskListItemsForClosedFiles")); + public static readonly Option2> Descriptors = new("TaskListOptionsStorage_Descriptors", TaskListOptions.Default.Descriptors); + public static readonly Option2 ComputeTaskListItemsForClosedFiles = new("TaskListOptionsStorage_ComputeTaskListItemsForClosedFiles", defaultValue: true); public static TaskListOptions GetTaskListOptions(this IGlobalOptionService globalOptions) => new() diff --git a/src/Features/LanguageServer/Protocol/Handler/Diagnostics/AbstractPullDiagnosticHandler.cs b/src/Features/LanguageServer/Protocol/Handler/Diagnostics/AbstractPullDiagnosticHandler.cs index 628d3a00716d3..7f6a19db9c498 100644 --- a/src/Features/LanguageServer/Protocol/Handler/Diagnostics/AbstractPullDiagnosticHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/Diagnostics/AbstractPullDiagnosticHandler.cs @@ -42,18 +42,6 @@ public AbstractDocumentPullDiagnosticHandler( internal abstract partial class AbstractPullDiagnosticHandler : ILspServiceRequestHandler where TDiagnosticsParams : IPartialResultParams { - /// - /// Diagnostic mode setting for Razor. This should always be as there is no push support in Razor. - /// This option is only for passing to the diagnostics service and can be removed when we switch all of Roslyn to LSP pull. - /// - private static readonly Option2 s_razorDiagnosticMode = new(nameof(InternalDiagnosticsOptions), "RazorDiagnosticMode", defaultValue: DiagnosticMode.LspPull); - - /// - /// Diagnostic mode setting for Live Share. This should always be as there is no push support in Live Share. - /// This option is only for passing to the diagnostics service and can be removed when we switch all of Roslyn to LSP pull. - /// - private static readonly Option2 s_liveShareDiagnosticMode = new(nameof(InternalDiagnosticsOptions), "LiveShareDiagnosticMode", defaultValue: DiagnosticMode.LspPull); - /// /// Special value we use to designate workspace diagnostics vs document diagnostics. Document diagnostics /// should always a workspace diagnostic as the former are 'live' @@ -161,6 +149,7 @@ protected abstract ValueTask> GetOrderedDiagno // last time we notified the client. Report back either to the client so they can update accordingly. var orderedSources = await GetOrderedDiagnosticSourcesAsync( diagnosticsParams, context, cancellationToken).ConfigureAwait(false); + context.TraceInformation($"Processing {orderedSources.Length} documents"); foreach (var diagnosticSource in orderedSources) @@ -255,8 +244,8 @@ private DiagnosticMode GetDiagnosticMode(RequestContext context) { var diagnosticModeOption = context.ServerKind switch { - WellKnownLspServerKinds.LiveShareLspServer => s_liveShareDiagnosticMode, - WellKnownLspServerKinds.RazorLspServer => s_razorDiagnosticMode, + WellKnownLspServerKinds.LiveShareLspServer => InternalDiagnosticsOptions.LiveShareDiagnosticMode, + WellKnownLspServerKinds.RazorLspServer => InternalDiagnosticsOptions.RazorDiagnosticMode, _ => InternalDiagnosticsOptions.NormalDiagnosticMode, }; @@ -375,6 +364,7 @@ LSP.VSDiagnostic CreateLspDiagnostic( Message = diagnosticData.Message, Severity = ConvertDiagnosticSeverity(diagnosticData.Severity), Tags = ConvertTags(diagnosticData), + DiagnosticRank = ConvertRank(diagnosticData), }; diagnostic.Range = GetRange(diagnosticData.DataLocation); @@ -429,6 +419,22 @@ static LSP.Range GetRange(DiagnosticDataLocation dataLocation) } } + private static VSDiagnosticRank? ConvertRank(DiagnosticData diagnosticData) + { + if (diagnosticData.Properties.TryGetValue(PullDiagnosticConstants.Priority, out var priority)) + { + return priority switch + { + PullDiagnosticConstants.Low => VSDiagnosticRank.Low, + PullDiagnosticConstants.Medium => VSDiagnosticRank.Default, + PullDiagnosticConstants.High => VSDiagnosticRank.High, + _ => null, + }; + } + + return null; + } + private static LSP.DiagnosticSeverity ConvertDiagnosticSeverity(DiagnosticSeverity severity) => severity switch { diff --git a/src/Features/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/TaskListDiagnosticSource.cs b/src/Features/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/TaskListDiagnosticSource.cs index db79c4e414211..8a4745c454604 100644 --- a/src/Features/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/TaskListDiagnosticSource.cs +++ b/src/Features/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/TaskListDiagnosticSource.cs @@ -14,9 +14,16 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler.Diagnostics; +using static PullDiagnosticConstants; + internal sealed class TaskListDiagnosticSource : AbstractDocumentDiagnosticSource { - private static readonly ImmutableArray s_todoCommentCustomTags = ImmutableArray.Create(PullDiagnosticConstants.TaskItemCustomTag); + private static readonly ImmutableArray s_todoCommentCustomTags = ImmutableArray.Create(TaskItemCustomTag); + + private static readonly ImmutableDictionary s_lowPriorityProperties = ImmutableDictionary.Empty.Add(Priority, Low); + private static readonly ImmutableDictionary s_mediumPriorityProperties = ImmutableDictionary.Empty.Add(Priority, Medium); + private static readonly ImmutableDictionary s_highPriorityProperties = ImmutableDictionary.Empty.Add(Priority, High); + private static Tuple, ImmutableArray> s_lastRequestedTokens = Tuple.Create(ImmutableArray.Empty, ImmutableArray.Empty); @@ -51,12 +58,21 @@ public override async Task> GetDiagnosticsAsync( isEnabledByDefault: true, warningLevel: 0, customTags: s_todoCommentCustomTags, - properties: ImmutableDictionary.Empty, + properties: GetProperties(i.Priority), projectId: this.Document.Project.Id, language: this.Document.Project.Language, location: new DiagnosticDataLocation(i.Span, this.Document.Id, mappedFileSpan: i.MappedSpan))); } + private static ImmutableDictionary GetProperties(TaskListItemPriority priority) + => priority switch + { + TaskListItemPriority.Low => s_lowPriorityProperties, + TaskListItemPriority.Medium => s_mediumPriorityProperties, + TaskListItemPriority.High => s_highPriorityProperties, + _ => s_mediumPriorityProperties, + }; + private static ImmutableArray GetAndCacheDescriptors(ImmutableArray tokenList) { var lastRequested = s_lastRequestedTokens; diff --git a/src/Features/LanguageServer/Protocol/Handler/Diagnostics/PullDiagnosticConstants.cs b/src/Features/LanguageServer/Protocol/Handler/Diagnostics/PullDiagnosticConstants.cs index 2a74e800e2e55..0384599ba952f 100644 --- a/src/Features/LanguageServer/Protocol/Handler/Diagnostics/PullDiagnosticConstants.cs +++ b/src/Features/LanguageServer/Protocol/Handler/Diagnostics/PullDiagnosticConstants.cs @@ -2,10 +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. -namespace Microsoft.CodeAnalysis.LanguageServer.Handler.Diagnostics +using System.Collections.Immutable; + +namespace Microsoft.CodeAnalysis.LanguageServer.Handler.Diagnostics; + +internal static class PullDiagnosticConstants { - internal static class PullDiagnosticConstants - { - public const string TaskItemCustomTag = nameof(TaskItemCustomTag); - } + public const string TaskItemCustomTag = nameof(TaskItemCustomTag); + + public const string Priority = nameof(Priority); + public const string Low = nameof(Low); + public const string Medium = nameof(Medium); + public const string High = nameof(High); } diff --git a/src/Features/LanguageServer/Protocol/LspOptions.cs b/src/Features/LanguageServer/Protocol/LspOptions.cs index cff00ff3fa61a..8e0232792982b 100644 --- a/src/Features/LanguageServer/Protocol/LspOptions.cs +++ b/src/Features/LanguageServer/Protocol/LspOptions.cs @@ -2,33 +2,22 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Collections.Immutable; -using System.Composition; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Options.Providers; namespace Microsoft.CodeAnalysis.LanguageServer { internal sealed class LspOptions { - private const string LocalRegistryPath = @"Roslyn\Internal\Lsp\"; - private const string FeatureName = "LspOptions"; - /// /// This sets the max list size we will return in response to a completion request. /// If there are more than this many items, we will set the isIncomplete flag on the returned completion list. /// - public static readonly Option2 MaxCompletionListSize = new(FeatureName, nameof(MaxCompletionListSize), defaultValue: 1000, - storageLocation: new LocalUserProfileStorageLocation(LocalRegistryPath + nameof(MaxCompletionListSize))); + public static readonly Option2 MaxCompletionListSize = new("LspOptions_MaxCompletionListSize", defaultValue: 1000); // Flag is defined in VisualStudio\Core\Def\PackageRegistration.pkgdef. - public static readonly Option2 LspEditorFeatureFlag = new(FeatureName, nameof(LspEditorFeatureFlag), defaultValue: false, - new FeatureFlagStorageLocation("Roslyn.LSP.Editor")); + public static readonly Option2 LspEditorFeatureFlag = new("LspOptions_LspEditorFeatureFlag", defaultValue: false); // Flag is defined in VisualStudio\Core\Def\PackageRegistration.pkgdef. - public static readonly Option2 LspSemanticTokensFeatureFlag = new(FeatureName, nameof(LspSemanticTokensFeatureFlag), defaultValue: false, - new FeatureFlagStorageLocation("Roslyn.LSP.SemanticTokens")); + public static readonly Option2 LspSemanticTokensFeatureFlag = new("LspOptions_LspSemanticTokensFeatureFlag", defaultValue: false); } } diff --git a/src/Features/LanguageServer/ProtocolUnitTests/Completion/CompletionTests.cs b/src/Features/LanguageServer/ProtocolUnitTests/Completion/CompletionTests.cs index ccc21b29886c9..de96b9f4a5a3b 100644 --- a/src/Features/LanguageServer/ProtocolUnitTests/Completion/CompletionTests.cs +++ b/src/Features/LanguageServer/ProtocolUnitTests/Completion/CompletionTests.cs @@ -210,7 +210,7 @@ void M() var solution = testLspServer.TestWorkspace.CurrentSolution; // Make sure the unimported types option is on by default. - testLspServer.TestWorkspace.GlobalOptions.SetGlobalOption(new OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), true); + testLspServer.TestWorkspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, true); var completionParams = CreateCompletionParams( testLspServer.GetLocations("caret").Single(), @@ -233,8 +233,7 @@ public async Task TestGetCompletionsUsesSnippetOptionAsync() await using var testLspServer = await CreateTestLspServerAsync(markup, s_vsCompletionCapabilities); - testLspServer.TestWorkspace.GlobalOptions.SetGlobalOption( - new OptionKey(CompletionOptionsStorage.SnippetsBehavior, LanguageNames.CSharp), SnippetsRule.NeverInclude); + testLspServer.TestWorkspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.SnippetsBehavior, LanguageNames.CSharp, SnippetsRule.NeverInclude); var completionParams = CreateCompletionParams( testLspServer.GetLocations("caret").Single(), @@ -1290,7 +1289,7 @@ void M() var globalOptions = testLspServer.TestWorkspace.GetService(); var listMaxSize = 1; - globalOptions.SetGlobalOption(new OptionKey(LspOptions.MaxCompletionListSize), listMaxSize); + globalOptions.SetGlobalOption(LspOptions.MaxCompletionListSize, listMaxSize); var results = await RunGetCompletionsAsync(testLspServer, completionParams).ConfigureAwait(false); Assert.True(results.IsIncomplete); diff --git a/src/Features/LanguageServer/ProtocolUnitTests/Diagnostics/AbstractPullDiagnosticTestsBase.cs b/src/Features/LanguageServer/ProtocolUnitTests/Diagnostics/AbstractPullDiagnosticTestsBase.cs index 81b3d728baf06..1b6a7d4881114 100644 --- a/src/Features/LanguageServer/ProtocolUnitTests/Diagnostics/AbstractPullDiagnosticTestsBase.cs +++ b/src/Features/LanguageServer/ProtocolUnitTests/Diagnostics/AbstractPullDiagnosticTestsBase.cs @@ -60,7 +60,7 @@ private protected static async Task> RunGet string? category = null) { var optionService = testLspServer.TestWorkspace.GetService(); - optionService.SetGlobalOption(new OptionKey(TaskListOptionsStorage.ComputeTaskListItemsForClosedFiles), includeTaskListItems); + optionService.SetGlobalOption(TaskListOptionsStorage.ComputeTaskListItemsForClosedFiles, includeTaskListItems); await testLspServer.WaitForDiagnosticsAsync(); if (useVSDiagnostics) @@ -284,11 +284,11 @@ private protected static InitializationOptions GetInitializationOptions( ClientCapabilities = useVSDiagnostics ? CapabilitiesWithVSExtensions : new LSP.ClientCapabilities(), OptionUpdater = (globalOptions) => { - globalOptions.SetGlobalOption(new OptionKey(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp), scope); - globalOptions.SetGlobalOption(new OptionKey(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.VisualBasic), scope); - globalOptions.SetGlobalOption(new OptionKey(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, InternalLanguageNames.TypeScript), scope); - globalOptions.SetGlobalOption(new OptionKey(InternalDiagnosticsOptions.NormalDiagnosticMode), mode); - globalOptions.SetGlobalOption(new OptionKey(SolutionCrawlerOptionsStorage.EnableDiagnosticsInSourceGeneratedFiles), true); + globalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp, scope); + globalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.VisualBasic, scope); + globalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, InternalLanguageNames.TypeScript, scope); + globalOptions.SetGlobalOption(InternalDiagnosticsOptions.NormalDiagnosticMode, mode); + globalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.EnableDiagnosticsInSourceGeneratedFiles, true); }, ServerKind = serverKind, SourceGeneratedMarkups = sourceGeneratedMarkups ?? Array.Empty() diff --git a/src/Features/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs b/src/Features/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs index ce2730069e1da..810b424a39a8c 100644 --- a/src/Features/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs +++ b/src/Features/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.SolutionCrawler; +using Microsoft.CodeAnalysis.TaskList; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; using Roslyn.Test.Utilities; @@ -213,7 +214,7 @@ public async Task TestNoDocumentDiagnosticsForOpenFilesIfDefaultAndFeatureFlagOf await OpenDocumentAsync(testLspServer, document); // Ensure we get no diagnostics when feature flag is off. - testLspServer.TestWorkspace.GlobalOptions.SetGlobalOption(new OptionKey(DiagnosticOptionsStorage.LspPullDiagnosticsFeatureFlag), false); + testLspServer.TestWorkspace.GlobalOptions.SetGlobalOption(DiagnosticOptionsStorage.LspPullDiagnosticsFeatureFlag, false); await Assert.ThrowsAsync(async () => await RunGetDocumentPullDiagnosticsAsync(testLspServer, document.GetURI(), useVSDiagnostics)); } @@ -231,7 +232,7 @@ public async Task TestDocumentDiagnosticsForOpenFilesIfDefaultAndFeatureFlagOn(b var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); await OpenDocumentAsync(testLspServer, document); - testLspServer.TestWorkspace.GlobalOptions.SetGlobalOption(new OptionKey(DiagnosticOptionsStorage.LspPullDiagnosticsFeatureFlag), true); + testLspServer.TestWorkspace.GlobalOptions.SetGlobalOption(DiagnosticOptionsStorage.LspPullDiagnosticsFeatureFlag, true); var results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, document.GetURI(), useVSDiagnostics); Assert.Equal("CS1513", results.Single().Diagnostics.Single().Code); @@ -699,7 +700,7 @@ class A }"; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync(markup, BackgroundAnalysisScope.OpenFiles, useVSDiagnostics); var firstLocation = testLspServer.GetLocations("first").Single().Range; - testLspServer.TestWorkspace.GlobalOptions.SetGlobalOption(new OptionKey(FadingOptions.FadeOutUnusedImports, LanguageNames.CSharp), true); + testLspServer.TestWorkspace.GlobalOptions.SetGlobalOption(FadingOptions.FadeOutUnusedImports, LanguageNames.CSharp, true); var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); @@ -738,7 +739,7 @@ class A }"; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync(markup, BackgroundAnalysisScope.OpenFiles, useVSDiagnostics); var firstLocation = testLspServer.GetLocations("first").Single().Range; - testLspServer.TestWorkspace.GlobalOptions.SetGlobalOption(new OptionKey(FadingOptions.FadeOutUnusedImports, LanguageNames.CSharp), false); + testLspServer.TestWorkspace.GlobalOptions.SetGlobalOption(FadingOptions.FadeOutUnusedImports, LanguageNames.CSharp, false); var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); @@ -856,6 +857,7 @@ class A { Assert.Equal(1, results.Length); Assert.Equal("TODO", results[0].Diagnostics.Single().Code); Assert.Equal("todo: goo", results[0].Diagnostics.Single().Message); + Assert.Equal(VSDiagnosticRank.Default, ((VSDiagnostic)results[0].Diagnostics.Single()).DiagnosticRank); } else { @@ -863,6 +865,33 @@ class A { } } + [Theory] + [InlineData("1", VSDiagnosticRank.Low)] + [InlineData("2", VSDiagnosticRank.Default)] + [InlineData("3", VSDiagnosticRank.High)] + public async Task TestWorkspaceTodoForClosedFilesWithFSAOffAndTodoOn_Priorities( + string priString, VSDiagnosticRank rank) + { + var markup1 = +@" +// todo: goo +class A { +}"; + await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync( + new[] { markup1 }, BackgroundAnalysisScope.OpenFiles, useVSDiagnostics: true); + + testLspServer.TestWorkspace.GlobalOptions.SetGlobalOption( + TaskListOptionsStorage.Descriptors, + ImmutableArray.Create("HACK:2", $"TODO:{priString}", "UNDONE:2", "UnresolvedMergeConflict:3")); + + var results = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics: true, includeTaskListItems: true, category: PullDiagnosticCategories.Task); + + Assert.Equal(1, results.Length); + Assert.Equal("TODO", results[0].Diagnostics.Single().Code); + Assert.Equal("todo: goo", results[0].Diagnostics.Single().Message); + Assert.Equal(rank, ((VSDiagnostic)results[0].Diagnostics.Single()).DiagnosticRank); + } + [Theory, CombinatorialData] public async Task TestWorkspaceTodoForClosedFilesWithFSAOnAndTodoOff(bool useVSDiagnostics) { diff --git a/src/Features/LanguageServer/ProtocolUnitTests/Options/LspOptionsTests.cs b/src/Features/LanguageServer/ProtocolUnitTests/Options/LspOptionsTests.cs new file mode 100644 index 0000000000000..42373baa001fa --- /dev/null +++ b/src/Features/LanguageServer/ProtocolUnitTests/Options/LspOptionsTests.cs @@ -0,0 +1,59 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.AddImport; +using Microsoft.CodeAnalysis.CodeGeneration; +using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.Editor.Test; +using Microsoft.CodeAnalysis.Editor.UnitTests; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Simplification; +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests.References; +public class LspOptionsTests : AbstractLanguageServerProtocolTests +{ + public LspOptionsTests(ITestOutputHelper? testOutputHelper) : base(testOutputHelper) + { + } + + protected override TestComposition Composition => EditorTestCompositions.LanguageServerProtocol + .AddParts(typeof(TestDocumentTrackingService)) + .AddParts(typeof(TestWorkspaceRegistrationService)); + + [Fact] + public async Task TestCanRetrieveCSharpOptionsWithOnlyLspLayer() + { + var markup = ""; + await using var testLspServer = await CreateTestLspServerAsync(markup); + var globalOptions = testLspServer.TestWorkspace.ExportProvider.GetExportedValue(); + var project = testLspServer.GetCurrentSolution().Projects.Single().Services; + Assert.NotNull(globalOptions.GetAddImportPlacementOptions(project)); + Assert.NotNull(globalOptions.GetCodeGenerationOptions(project)); + Assert.NotNull(globalOptions.GetCodeStyleOptions(project)); + Assert.NotNull(globalOptions.GetSyntaxFormattingOptions(project)); + Assert.NotNull(globalOptions.GetSimplifierOptions(project)); + } + + [Fact] + public async Task TestCanRetrieveVisualBasicOptionsWithOnlyLspLayer() + { + var markup = ""; + await using var testLspServer = await CreateVisualBasicTestLspServerAsync(markup); + var globalOptions = testLspServer.TestWorkspace.ExportProvider.GetExportedValue(); + var project = testLspServer.GetCurrentSolution().Projects.Single().Services; + Assert.NotNull(globalOptions.GetAddImportPlacementOptions(project)); + Assert.NotNull(globalOptions.GetCodeGenerationOptions(project)); + Assert.NotNull(globalOptions.GetCodeStyleOptions(project)); + Assert.NotNull(globalOptions.GetSyntaxFormattingOptions(project)); + Assert.NotNull(globalOptions.GetSimplifierOptions(project)); + } +} diff --git a/src/Features/LanguageServer/ProtocolUnitTests/VSTypeScriptHandlerTests.cs b/src/Features/LanguageServer/ProtocolUnitTests/VSTypeScriptHandlerTests.cs index f2144c37197dc..1e3d8caf143f2 100644 --- a/src/Features/LanguageServer/ProtocolUnitTests/VSTypeScriptHandlerTests.cs +++ b/src/Features/LanguageServer/ProtocolUnitTests/VSTypeScriptHandlerTests.cs @@ -65,7 +65,7 @@ public async Task TestRoslynTypeScriptHandlerInvoked() var options = new InitializationOptions() { - OptionUpdater = globalOptions => globalOptions.SetGlobalOption(new OptionKey(InternalDiagnosticsOptions.NormalDiagnosticMode), DiagnosticMode.LspPull) + OptionUpdater = globalOptions => globalOptions.SetGlobalOption(InternalDiagnosticsOptions.NormalDiagnosticMode, DiagnosticMode.LspPull) }; await using var testLspServer = await CreateTsTestLspServerAsync(workspaceXml, options); diff --git a/src/Features/Lsif/Generator/Generator.cs b/src/Features/Lsif/Generator/Generator.cs index c3154b5b99a85..0c6033555dfc5 100644 --- a/src/Features/Lsif/Generator/Generator.cs +++ b/src/Features/Lsif/Generator/Generator.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.IO; +using System.Linq; using System.Reflection; using System.Text; using System.Threading; @@ -57,16 +58,18 @@ internal sealed class Generator }; private readonly ILsifJsonWriter _lsifJsonWriter; + private readonly TextWriter _logFile; private readonly IdFactory _idFactory = new IdFactory(); - private Generator(ILsifJsonWriter lsifJsonWriter) + private Generator(ILsifJsonWriter lsifJsonWriter, TextWriter logFile) { _lsifJsonWriter = lsifJsonWriter; + _logFile = logFile; } - public static Generator CreateAndWriteCapabilitiesVertex(ILsifJsonWriter lsifJsonWriter) + public static Generator CreateAndWriteCapabilitiesVertex(ILsifJsonWriter lsifJsonWriter, TextWriter logFile) { - var generator = new Generator(lsifJsonWriter); + var generator = new Generator(lsifJsonWriter, logFile); // Pass the set of supported SemanticTokenTypes. Order must match // the order used for serialization of semantic tokens array. This @@ -132,9 +135,11 @@ public async Task GenerateForProjectAsync( } }; + var documents = (await project.GetAllRegularAndSourceGeneratedDocumentsAsync(cancellationToken)).ToList(); var tasks = new List(); - foreach (var document in await project.GetAllRegularAndSourceGeneratedDocumentsAsync(cancellationToken)) + foreach (var document in documents) { + // Add a task for each document -- we'll keep them 1:1 for exception reporting later. tasks.Add(Task.Run(async () => { // We generate the document contents into an in-memory copy, and then write that out at once at the end. This @@ -153,11 +158,35 @@ public async Task GenerateForProjectAsync( }, cancellationToken)); } - await Task.WhenAll(tasks); + try + { + await Task.WhenAll(tasks); + } + catch + { + // We ran into some exceptions while processing documents, let's log it along with the document that failed + var exceptions = new List(); - _lsifJsonWriter.Write(Edge.Create("contains", projectVertex.GetId(), documentIds.ToArray(), _idFactory)); + for (var i = 0; i < documents.Count; i++) + { + if (tasks[i].IsFaulted) + { + var exception = tasks[i].Exception!.InnerExceptions.Single(); + exceptions.Add(exception); - _lsifJsonWriter.Write(new Event(Event.EventKind.End, projectVertex.GetId(), _idFactory)); + await _logFile.WriteLineAsync($"Exception while processing {documents[i].FilePath}:"); + await _logFile.WriteLineAsync(exception.ToString()); + } + } + + // Rethrow so we properly report this as a top-level failure + throw new AggregateException($"Exceptions were thrown while processing documents in {project.FilePath}", exceptions); + } + finally + { + _lsifJsonWriter.Write(Edge.Create("contains", projectVertex.GetId(), documentIds.ToArray(), _idFactory)); + _lsifJsonWriter.Write(new Event(Event.EventKind.End, projectVertex.GetId(), _idFactory)); + } } /// diff --git a/src/Features/Lsif/Generator/Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.csproj b/src/Features/Lsif/Generator/Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.csproj index 21acbe05bb2b3..f104cf6a40b3d 100644 --- a/src/Features/Lsif/Generator/Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.csproj +++ b/src/Features/Lsif/Generator/Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.csproj @@ -72,7 +72,7 @@ - + diff --git a/src/Features/Lsif/Generator/Program.cs b/src/Features/Lsif/Generator/Program.cs index 4932f9d71c199..4a7c7009bda5b 100644 --- a/src/Features/Lsif/Generator/Program.cs +++ b/src/Features/Lsif/Generator/Program.cs @@ -180,7 +180,7 @@ private static async Task GenerateWithMSBuildWorkspaceAsync( var options = GeneratorOptions.Default; await logFile.WriteLineAsync($"Load completed in {solutionLoadStopwatch.Elapsed.ToDisplayString()}."); - var lsifGenerator = Generator.CreateAndWriteCapabilitiesVertex(lsifWriter); + var lsifGenerator = Generator.CreateAndWriteCapabilitiesVertex(lsifWriter, logFile); var totalTimeInGenerationAndCompilationFetchStopwatch = Stopwatch.StartNew(); var totalTimeInGenerationPhase = TimeSpan.Zero; @@ -218,7 +218,7 @@ private static async Task GenerateFromCompilerInvocationAsync( await logFile.WriteLineAsync($"Load of the project completed in {compilerInvocationLoadStopwatch.Elapsed.ToDisplayString()}."); var generationStopwatch = Stopwatch.StartNew(); - var lsifGenerator = Generator.CreateAndWriteCapabilitiesVertex(lsifWriter); + var lsifGenerator = Generator.CreateAndWriteCapabilitiesVertex(lsifWriter, logFile); await lsifGenerator.GenerateForProjectAsync(project, GeneratorOptions.Default, cancellationToken); await logFile.WriteLineAsync($"Generation for {project.FilePath} completed in {generationStopwatch.Elapsed.ToDisplayString()}."); @@ -234,7 +234,7 @@ private static async Task GenerateFromBinaryLogAsync( await logFile.WriteLineAsync($"Load of the binlog complete; {msbuildInvocations.Length} invocations were found."); - var lsifGenerator = Generator.CreateAndWriteCapabilitiesVertex(lsifWriter); + var lsifGenerator = Generator.CreateAndWriteCapabilitiesVertex(lsifWriter, logFile); foreach (var msbuildInvocation in msbuildInvocations) { diff --git a/src/Features/Lsif/GeneratorTest/Utilities/TestLsifOutput.vb b/src/Features/Lsif/GeneratorTest/Utilities/TestLsifOutput.vb index faf44cabc6fd4..9605606563494 100644 --- a/src/Features/Lsif/GeneratorTest/Utilities/TestLsifOutput.vb +++ b/src/Features/Lsif/GeneratorTest/Utilities/TestLsifOutput.vb @@ -11,6 +11,7 @@ Imports LSP = Microsoft.VisualStudio.LanguageServer.Protocol Imports Roslyn.Utilities Imports Microsoft.CodeAnalysis.Test.Utilities Imports System.Threading +Imports System.IO Namespace Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.UnitTests.Utilities Friend Class TestLsifOutput @@ -45,7 +46,8 @@ Namespace Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.UnitTests.U ' world function of the indexer. Assert.Equal(workspace.Composition, TestComposition) - Dim lsifGenerator = Generator.CreateAndWriteCapabilitiesVertex(jsonWriter) + Dim log = New StringWriter() + Dim lsifGenerator = Generator.CreateAndWriteCapabilitiesVertex(jsonWriter, log) For Each project In workspace.CurrentSolution.Projects Dim compilation = Await project.GetCompilationAsync() @@ -55,6 +57,9 @@ Namespace Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.UnitTests.U Await lsifGenerator.GenerateForProjectAsync(project, GeneratorOptions.Default, CancellationToken.None) Next + + ' The only things would have logged were an error, so this should be empty + Assert.Empty(log.ToString()) End Function Public Function GetElementById(Of T As Element)(id As Id(Of T)) As T diff --git a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.VisualBasicCodeGenerator.vb b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.VisualBasicCodeGenerator.vb index b18200622ecbc..882887b2ae452 100644 --- a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.VisualBasicCodeGenerator.vb +++ b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.VisualBasicCodeGenerator.vb @@ -401,7 +401,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExtractMethod Dim initializer = If(givenInitializer, If(shouldInitializeWithNothing, SyntaxFactory.NothingLiteralExpression(SyntaxFactory.Token(SyntaxKind.NothingKeyword)), Nothing)) - Dim variableType = variable.GetVariableType(Me.SemanticDocument) + Dim variableType = variable.GetVariableType() Dim typeNode = variableType.GenerateTypeSyntax() Dim names = SyntaxFactory.SingletonSeparatedList(SyntaxFactory.ModifiedIdentifier(SyntaxFactory.Identifier(variable.Name))) diff --git a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.vb b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.vb index 517b9feb0380f..b7a769f619cba 100644 --- a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.vb +++ b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.vb @@ -105,7 +105,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExtractMethod Dim symbolInfo = binding.GetSpeculativeSymbolInfo(contextNode.SpanStart, typeName, SpeculativeBindingOption.BindAsTypeOrNamespace) Dim currentType = TryCast(symbolInfo.Symbol, ITypeSymbol) - If Not SymbolEqualityComparer.Default.Equals(currentType, typeParameter) Then + If Not SymbolEqualityComparer.Default.Equals(currentType, binding.ResolveType(typeParameter)) Then Return New OperationStatus(OperationStatusFlag.BestEffort, String.Format(FeaturesResources.Type_parameter_0_is_hidden_by_another_type_parameter_1, typeParameter.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat), diff --git a/src/Features/VisualBasic/Portable/MakeMethodAsynchronous/VisualBasicMakeMethodAsynchronousCodeFixProvider.vb b/src/Features/VisualBasic/Portable/MakeMethodAsynchronous/VisualBasicMakeMethodAsynchronousCodeFixProvider.vb index 0d80f191474ff..e8dafd2c5c2e1 100644 --- a/src/Features/VisualBasic/Portable/MakeMethodAsynchronous/VisualBasicMakeMethodAsynchronousCodeFixProvider.vb +++ b/src/Features/VisualBasic/Portable/MakeMethodAsynchronous/VisualBasicMakeMethodAsynchronousCodeFixProvider.vb @@ -69,7 +69,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.MakeMethodAsynchronous Return FixMultiLineLambdaExpression(DirectCast(node, MultiLineLambdaExpressionSyntax)) ElseIf node.IsKind(SyntaxKind.SubBlock) Then - Return FixSubBlock(keepVoid, DirectCast(node, MethodBlockSyntax), knownTypes._taskType) + Return FixSubBlock(keepVoid, DirectCast(node, MethodBlockSyntax), knownTypes.TaskType) Else Return FixFunctionBlock( methodSymbolOpt, DirectCast(node, MethodBlockSyntax), knownTypes) @@ -82,7 +82,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.MakeMethodAsynchronous If Not IsTaskLike(methodSymbol.ReturnType, knownTypes) Then ' if the current return type is not already task-list, then wrap it in Task(of ...) - Dim returnType = knownTypes._taskOfTType.Construct(methodSymbol.ReturnType).GenerateTypeSyntax().WithAdditionalAnnotations(Simplifier.AddImportsAnnotation) + Dim returnType = knownTypes.TaskOfTType.Construct(methodSymbol.ReturnType).GenerateTypeSyntax().WithAdditionalAnnotations(Simplifier.AddImportsAnnotation) newFunctionStatement = newFunctionStatement.WithAsClause( newFunctionStatement.AsClause.WithType(returnType)) End If diff --git a/src/Features/VisualBasic/Portable/MakeMethodSynchronous/VisualBasicMakeMethodSynchronousCodeFixProvider.vb b/src/Features/VisualBasic/Portable/MakeMethodSynchronous/VisualBasicMakeMethodSynchronousCodeFixProvider.vb index 8995cb486e405..93eebdc5e6bee 100644 --- a/src/Features/VisualBasic/Portable/MakeMethodSynchronous/VisualBasicMakeMethodSynchronousCodeFixProvider.vb +++ b/src/Features/VisualBasic/Portable/MakeMethodSynchronous/VisualBasicMakeMethodSynchronousCodeFixProvider.vb @@ -56,12 +56,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.MakeMethodSynchronous ' if this returns Task(of T), then we want to convert this to a T returning function. ' if this returns Task, then we want to convert it to a Sub method. - If methodSymbol.ReturnType.OriginalDefinition.Equals(knownTypes._taskOfTType) Then + If methodSymbol.ReturnType.OriginalDefinition.Equals(knownTypes.TaskOfTType) Then Dim newAsClause = functionStatement.AsClause.WithType(methodSymbol.ReturnType.GetTypeArguments()(0).GenerateTypeSyntax()) Dim newFunctionStatement = functionStatement.WithAsClause(newAsClause) newFunctionStatement = RemoveAsyncModifierHelpers.RemoveAsyncKeyword(newFunctionStatement) Return node.WithSubOrFunctionStatement(newFunctionStatement) - ElseIf Equals(methodSymbol.ReturnType.OriginalDefinition, knownTypes._taskType) Then + ElseIf Equals(methodSymbol.ReturnType.OriginalDefinition, knownTypes.TaskType) Then ' Convert this to a 'Sub' method. Dim subStatement = SyntaxFactory.SubStatement( functionStatement.AttributeLists, diff --git a/src/Features/VisualBasic/Portable/Wrapping/VisualBasicSyntaxWrappingOptions.vb b/src/Features/VisualBasic/Portable/Wrapping/VisualBasicSyntaxWrappingOptions.vb index 2b5599ca17e12..a8dd1742d5340 100644 --- a/src/Features/VisualBasic/Portable/Wrapping/VisualBasicSyntaxWrappingOptions.vb +++ b/src/Features/VisualBasic/Portable/Wrapping/VisualBasicSyntaxWrappingOptions.vb @@ -7,6 +7,7 @@ Imports Microsoft.CodeAnalysis.CodeStyle Imports Microsoft.CodeAnalysis.Wrapping Imports Microsoft.CodeAnalysis.Diagnostics Imports Microsoft.CodeAnalysis.VisualBasic.Formatting +Imports Microsoft.CodeAnalysis.Options Namespace Microsoft.CodeAnalysis.VisualBasic.Wrapping @@ -21,11 +22,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Wrapping MyBase.New(formattingOptions, wrappingColumn, operatorPlacement) End Sub - Public Shared Function Create(options As AnalyzerConfigOptions, ideOptions As CodeActionOptions) As VisualBasicSyntaxWrappingOptions + Public Shared Function Create(options As IOptionsReader, fallbackOptions As CodeActionOptions) As VisualBasicSyntaxWrappingOptions Return New VisualBasicSyntaxWrappingOptions( - formattingOptions:=VisualBasicSyntaxFormattingOptions.Create(options, DirectCast(ideOptions.CleanupOptions.FormattingOptions, VisualBasicSyntaxFormattingOptions)), - operatorPlacement:=options.GetOption(CodeStyleOptions2.OperatorPlacementWhenWrapping), - wrappingColumn:=ideOptions.WrappingColumn) + formattingOptions:=VisualBasicSyntaxFormattingOptions.Create(options, DirectCast(fallbackOptions.CleanupOptions.FormattingOptions, VisualBasicSyntaxFormattingOptions)), + operatorPlacement:=options.GetOption(CodeStyleOptions2.OperatorPlacementWhenWrapping, fallbackOptions.CodeStyleOptions.Common.OperatorPlacementWhenWrapping), + wrappingColumn:=fallbackOptions.WrappingColumn) End Function End Class End Namespace diff --git a/src/Features/VisualBasic/Portable/Wrapping/VisualBasicWrappingCodeRefactoringProvider.vb b/src/Features/VisualBasic/Portable/Wrapping/VisualBasicWrappingCodeRefactoringProvider.vb index c0d2488dd6488..8fc1329dfde96 100644 --- a/src/Features/VisualBasic/Portable/Wrapping/VisualBasicWrappingCodeRefactoringProvider.vb +++ b/src/Features/VisualBasic/Portable/Wrapping/VisualBasicWrappingCodeRefactoringProvider.vb @@ -8,6 +8,7 @@ Imports System.Diagnostics.CodeAnalysis Imports Microsoft.CodeAnalysis.CodeActions Imports Microsoft.CodeAnalysis.CodeRefactorings Imports Microsoft.CodeAnalysis.Diagnostics +Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.VisualBasic.Wrapping.BinaryExpression Imports Microsoft.CodeAnalysis.VisualBasic.Wrapping.ChainedExpression Imports Microsoft.CodeAnalysis.VisualBasic.Wrapping.SeparatedSyntaxList @@ -32,7 +33,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Wrapping MyBase.New(s_wrappers) End Sub - Protected Overrides Function GetWrappingOptions(options As AnalyzerConfigOptions, ideOptions As CodeActionOptions) As SyntaxWrappingOptions + Protected Overrides Function GetWrappingOptions(options As IOptionsReader, ideOptions As CodeActionOptions) As SyntaxWrappingOptions Return VisualBasicSyntaxWrappingOptions.Create(options, ideOptions) End Function End Class diff --git a/src/Tools/AnalyzerRunner/IncrementalAnalyzerRunner.cs b/src/Tools/AnalyzerRunner/IncrementalAnalyzerRunner.cs index 513279608e0e9..76be36386db05 100644 --- a/src/Tools/AnalyzerRunner/IncrementalAnalyzerRunner.cs +++ b/src/Tools/AnalyzerRunner/IncrementalAnalyzerRunner.cs @@ -43,8 +43,8 @@ public async Task RunAsync(CancellationToken cancellationToken) var exportProvider = _workspace.Services.SolutionServices.ExportProvider; var globalOptions = exportProvider.GetExports().Single().Value; - globalOptions.SetGlobalOption(new OptionKey(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp), _options.AnalysisScope); - globalOptions.SetGlobalOption(new OptionKey(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.VisualBasic), _options.AnalysisScope); + globalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp, _options.AnalysisScope); + globalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.VisualBasic, _options.AnalysisScope); var workspaceConfigurationService = (AnalyzerRunnerWorkspaceConfigurationService)_workspace.Services.GetRequiredService(); workspaceConfigurationService.Options = new(CacheStorage: usePersistentStorage ? StorageDatabase.SQLite : StorageDatabase.None); diff --git a/src/Tools/ExternalAccess/FSharp/FSharpGlobalOptions.cs b/src/Tools/ExternalAccess/FSharp/FSharpGlobalOptions.cs index 8fa131829ffbb..5cc39b805f5d3 100644 --- a/src/Tools/ExternalAccess/FSharp/FSharpGlobalOptions.cs +++ b/src/Tools/ExternalAccess/FSharp/FSharpGlobalOptions.cs @@ -28,13 +28,13 @@ public FSharpGlobalOptions(IGlobalOptionService globalOptions) public bool BlockForCompletionItems { get => _globalOptions.GetOption(CompletionViewOptions.BlockForCompletionItems, LanguageNames.FSharp); - set => _globalOptions.SetGlobalOption(new OptionKey(CompletionViewOptions.BlockForCompletionItems, LanguageNames.FSharp), value); + set => _globalOptions.SetGlobalOption(CompletionViewOptions.BlockForCompletionItems, LanguageNames.FSharp, value); } public void SetBackgroundAnalysisScope(bool openFilesOnly) { _globalOptions.SetGlobalOption( - new OptionKey(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.FSharp), + SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.FSharp, openFilesOnly ? BackgroundAnalysisScope.OpenFiles : BackgroundAnalysisScope.FullSolution); } } diff --git a/src/Tools/ExternalAccess/FSharp/InternalAPI.Unshipped.txt b/src/Tools/ExternalAccess/FSharp/InternalAPI.Unshipped.txt index 07acdb121915e..83c4fddec950b 100644 --- a/src/Tools/ExternalAccess/FSharp/InternalAPI.Unshipped.txt +++ b/src/Tools/ExternalAccess/FSharp/InternalAPI.Unshipped.txt @@ -382,6 +382,10 @@ static Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor.Implementation.Debugg static Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor.Implementation.Debugging.FSharpBreakpointResolutionResult.CreateSpanResult(Microsoft.CodeAnalysis.Document! document, Microsoft.CodeAnalysis.Text.TextSpan textSpan, string? locationNameOpt = null) -> Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor.Implementation.Debugging.FSharpBreakpointResolutionResult! static Microsoft.CodeAnalysis.ExternalAccess.FSharp.FSharpDocumentSpan.operator !=(Microsoft.CodeAnalysis.ExternalAccess.FSharp.FSharpDocumentSpan d1, Microsoft.CodeAnalysis.ExternalAccess.FSharp.FSharpDocumentSpan d2) -> bool static Microsoft.CodeAnalysis.ExternalAccess.FSharp.FSharpDocumentSpan.operator ==(Microsoft.CodeAnalysis.ExternalAccess.FSharp.FSharpDocumentSpan d1, Microsoft.CodeAnalysis.ExternalAccess.FSharp.FSharpDocumentSpan d2) -> bool +static Microsoft.CodeAnalysis.ExternalAccess.FSharp.LanguageServices.FSharpVisualStudioWorkspaceExtensions.GetMetadata(this Microsoft.VisualStudio.LanguageServices.VisualStudioWorkspace! workspace, string! fullPath, System.DateTime snapshotTimestamp) -> Microsoft.CodeAnalysis.Metadata! +static Microsoft.CodeAnalysis.ExternalAccess.FSharp.LanguageServices.FSharpVisualStudioWorkspaceExtensions.GetOrCreateProjectIdForPath(this Microsoft.VisualStudio.LanguageServices.VisualStudioWorkspace! workspace, string! filePath, string! projectDisplayName) -> Microsoft.CodeAnalysis.ProjectId! +static Microsoft.CodeAnalysis.ExternalAccess.FSharp.LanguageServices.FSharpVisualStudioWorkspaceExtensions.GetProjectFilePath(this Microsoft.VisualStudio.LanguageServices.VisualStudioWorkspace! workspace, Microsoft.CodeAnalysis.ProjectId! projectId) -> string? +static Microsoft.CodeAnalysis.ExternalAccess.FSharp.LanguageServices.FSharpVisualStudioWorkspaceExtensions.TryGetProjectIdByBinPath(this Microsoft.VisualStudio.LanguageServices.VisualStudioWorkspace! workspace, string! filePath, out Microsoft.CodeAnalysis.ProjectId? projectId) -> bool ~abstract Microsoft.CodeAnalysis.ExternalAccess.FSharp.Completion.FSharpCommonCompletionProviderBase.GetTextChangeAsync(System.Func> baseGetTextChangeAsync, Microsoft.CodeAnalysis.Completion.CompletionItem selectedItem, char? ch, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task ~abstract Microsoft.CodeAnalysis.ExternalAccess.FSharp.Completion.FSharpCommonCompletionProviderBase.IsInsertionTrigger(Microsoft.CodeAnalysis.Text.SourceText text, int insertedCharacterPosition) -> bool ~abstract Microsoft.CodeAnalysis.ExternalAccess.FSharp.Completion.FSharpCommonCompletionProviderBase.ProvideCompletionsAsync(Microsoft.CodeAnalysis.Completion.CompletionContext context) -> System.Threading.Tasks.Task @@ -549,10 +553,6 @@ static Microsoft.CodeAnalysis.ExternalAccess.FSharp.FSharpDocumentSpan.operator ~static Microsoft.CodeAnalysis.ExternalAccess.FSharp.FindUsages.FSharpDefinitionItem.CreateNonNavigableItem(System.Collections.Immutable.ImmutableArray tags, System.Collections.Immutable.ImmutableArray displayParts, System.Collections.Immutable.ImmutableArray originationParts) -> Microsoft.CodeAnalysis.ExternalAccess.FSharp.FindUsages.FSharpDefinitionItem ~static Microsoft.CodeAnalysis.ExternalAccess.FSharp.FSharpEditorFeaturesResources.You_cannot_rename_this_element.get -> string ~static Microsoft.CodeAnalysis.ExternalAccess.FSharp.FSharpGlyphTags.GetTags(Microsoft.CodeAnalysis.ExternalAccess.FSharp.FSharpGlyph glyph) -> System.Collections.Immutable.ImmutableArray -~static Microsoft.CodeAnalysis.ExternalAccess.FSharp.LanguageServices.FSharpVisualStudioWorkspaceExtensions.GetMetadata(this Microsoft.VisualStudio.LanguageServices.VisualStudioWorkspace workspace, string fullPath, System.DateTime snapshotTimestamp) -> Microsoft.CodeAnalysis.Metadata -~static Microsoft.CodeAnalysis.ExternalAccess.FSharp.LanguageServices.FSharpVisualStudioWorkspaceExtensions.GetOrCreateProjectIdForPath(this Microsoft.VisualStudio.LanguageServices.VisualStudioWorkspace workspace, string filePath, string projectDisplayName) -> Microsoft.CodeAnalysis.ProjectId -~static Microsoft.CodeAnalysis.ExternalAccess.FSharp.LanguageServices.FSharpVisualStudioWorkspaceExtensions.GetProjectFilePath(this Microsoft.VisualStudio.LanguageServices.VisualStudioWorkspace workspace, Microsoft.CodeAnalysis.ProjectId projectId) -> string -~static Microsoft.CodeAnalysis.ExternalAccess.FSharp.LanguageServices.FSharpVisualStudioWorkspaceExtensions.TryGetProjectIdByBinPath(this Microsoft.VisualStudio.LanguageServices.VisualStudioWorkspace workspace, string filePath, out Microsoft.CodeAnalysis.ProjectId projectId) -> bool ~static Microsoft.CodeAnalysis.ExternalAccess.FSharp.NavigateTo.FSharpNavigateToItemKind.Class.get -> string ~static Microsoft.CodeAnalysis.ExternalAccess.FSharp.NavigateTo.FSharpNavigateToItemKind.Constant.get -> string ~static Microsoft.CodeAnalysis.ExternalAccess.FSharp.NavigateTo.FSharpNavigateToItemKind.Delegate.get -> string diff --git a/src/Tools/ExternalAccess/FSharp/LanguageServices/FSharpVisualStudioWorkspaceExtensions.cs b/src/Tools/ExternalAccess/FSharp/LanguageServices/FSharpVisualStudioWorkspaceExtensions.cs index 31328f45cb636..00bb1e2a144e5 100644 --- a/src/Tools/ExternalAccess/FSharp/LanguageServices/FSharpVisualStudioWorkspaceExtensions.cs +++ b/src/Tools/ExternalAccess/FSharp/LanguageServices/FSharpVisualStudioWorkspaceExtensions.cs @@ -2,9 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; using Microsoft.VisualStudio.LanguageServices; using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; @@ -14,59 +14,40 @@ internal static class FSharpVisualStudioWorkspaceExtensions { public static Metadata GetMetadata(this VisualStudioWorkspace workspace, string fullPath, DateTime snapshotTimestamp) { - var metadataReferenceProvider = workspace.Services.GetService(); + var metadataReferenceProvider = workspace.Services.GetRequiredService(); return metadataReferenceProvider.GetMetadata(fullPath, snapshotTimestamp); } [Obsolete("When Roslyn/ProjectSystem integration is finished, don't use this.")] - public static bool TryGetProjectIdByBinPath(this VisualStudioWorkspace workspace, string filePath, out ProjectId projectId) + public static bool TryGetProjectIdByBinPath(this VisualStudioWorkspace workspace, string filePath, [NotNullWhen(true)] out ProjectId? projectId) { - if (workspace is VisualStudioWorkspaceImpl) + var projects = workspace.CurrentSolution.Projects.Where(p => string.Equals(p.OutputFilePath, filePath, StringComparison.OrdinalIgnoreCase)).ToList(); + + if (projects.Count == 1) + { + projectId = projects[0].Id; + return true; + } + else { - var impl = workspace as VisualStudioWorkspaceImpl; - if (impl.ProjectTracker.TryGetProjectByBinPath(filePath, out var project)) - { - projectId = project.Id; - return true; - } - else - { - projectId = null; - return false; - } + projectId = null; + return false; } - projectId = null; - return false; } [Obsolete("When Roslyn/ProjectSystem integration is finished, don't use this.")] public static ProjectId GetOrCreateProjectIdForPath(this VisualStudioWorkspace workspace, string filePath, string projectDisplayName) { - if (workspace is VisualStudioWorkspaceImpl) - { - var impl = workspace as VisualStudioWorkspaceImpl; - return impl.ProjectTracker.GetOrCreateProjectIdForPath(filePath, projectDisplayName); - } - return null; + // HACK: to keep F# working, we will ensure we return the ProjectId if there is a project that matches this path. Otherwise, we'll just return + // a random ProjectId, which is sufficient for their needs. They'll simply observe there is no project with that ID, and then go and create a + // new project. Then they call this function again, and fetch the real ID. + return workspace.CurrentSolution.Projects.FirstOrDefault(p => p.FilePath == filePath)?.Id ?? ProjectId.CreateNewId("ProjectNotFound"); } [Obsolete("When Roslyn/ProjectSystem integration is finished, don't use this.")] - public static string GetProjectFilePath(this VisualStudioWorkspace workspace, ProjectId projectId) + public static string? GetProjectFilePath(this VisualStudioWorkspace workspace, ProjectId projectId) { - if (workspace is VisualStudioWorkspaceImpl) - { - var impl = workspace as VisualStudioWorkspaceImpl; - var project = impl.ProjectTracker.GetProject(projectId); - if (project != null) - { - return project.ProjectFilePath; - } - else - { - return null; - } - } - return null; + return workspace.CurrentSolution.GetProject(projectId)?.FilePath; } } } diff --git a/src/Tools/ExternalAccess/Razor/RazorGlobalOptions.cs b/src/Tools/ExternalAccess/Razor/RazorGlobalOptions.cs index 62534a071b68c..a0a19faf32edb 100644 --- a/src/Tools/ExternalAccess/Razor/RazorGlobalOptions.cs +++ b/src/Tools/ExternalAccess/Razor/RazorGlobalOptions.cs @@ -32,13 +32,13 @@ public RazorAutoFormattingOptions GetAutoFormattingOptions() public bool UseTabs { get => _globalOptions.GetOption(RazorLineFormattingOptionsStorage.UseTabs); - set => _globalOptions.SetGlobalOption(new OptionKey(RazorLineFormattingOptionsStorage.UseTabs), value); + set => _globalOptions.SetGlobalOption(RazorLineFormattingOptionsStorage.UseTabs, value); } public int TabSize { get => _globalOptions.GetOption(RazorLineFormattingOptionsStorage.TabSize); - set => _globalOptions.SetGlobalOption(new OptionKey(RazorLineFormattingOptionsStorage.TabSize), value); + set => _globalOptions.SetGlobalOption(RazorLineFormattingOptionsStorage.TabSize, value); } #pragma warning disable IDE0060 // Remove unused parameter @@ -55,20 +55,24 @@ private sealed class TestGlobalOptionService : IGlobalOptionService public event EventHandler? OptionChanged; #pragma warning restore - public T GetOption(PerLanguageOption2 option, string? languageName) + public T GetOption(PerLanguageOption2 option, string languageName) => default!; public T GetOption(Option2 option) => throw new NotImplementedException(); - public object? GetOption(OptionKey optionKey) => throw new NotImplementedException(); + public T GetOption(OptionKey2 optionKey) => throw new NotImplementedException(); public ImmutableArray GetOptions(ImmutableArray optionKeys) => throw new NotImplementedException(); - public IEnumerable GetRegisteredOptions() => throw new NotImplementedException(); - public ImmutableHashSet GetRegisteredSerializableOptions(ImmutableHashSet languages) => throw new NotImplementedException(); - public void RefreshOption(OptionKey optionKey, object? newValue) => throw new NotImplementedException(); - public void RegisterWorkspace(Workspace workspace) => throw new NotImplementedException(); - public void SetGlobalOption(OptionKey optionKey, object? value) => throw new NotImplementedException(); - public void SetGlobalOptions(ImmutableArray optionKeys, ImmutableArray values) => throw new NotImplementedException(); - public void SetOptions(OptionSet optionSet, IEnumerable optionKeys) => throw new NotImplementedException(); - public void UnregisterWorkspace(Workspace workspace) => throw new NotImplementedException(); + public bool RefreshOption(OptionKey2 optionKey, object? newValue) => throw new NotImplementedException(); + public ImmutableArray GetOptions(ImmutableArray optionKeys) => throw new NotImplementedException(); + public void SetGlobalOption(Option2 option, T value) => throw new NotImplementedException(); + public void SetGlobalOption(PerLanguageOption2 option, string language, T value) => throw new NotImplementedException(); + public void SetGlobalOption(OptionKey2 optionKey, object? value) => throw new NotImplementedException(); + public bool SetGlobalOptions(ImmutableArray> options) => throw new NotImplementedException(); + + bool IOptionsReader.TryGetOption(OptionKey2 optionKey, out T value) + { + value = GetOption(optionKey); + return true; + } } } } diff --git a/src/Tools/ExternalAccess/RazorCompiler/GeneratorExtensions.cs b/src/Tools/ExternalAccess/RazorCompiler/GeneratorExtensions.cs new file mode 100644 index 0000000000000..bc7d9f43af7be --- /dev/null +++ b/src/Tools/ExternalAccess/RazorCompiler/GeneratorExtensions.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; +using System.Collections.Immutable; +using System.Threading; +using Microsoft.CodeAnalysis.PooledObjects; + +namespace Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler +{ + internal static partial class GeneratorExtensions + { + public static void RegisterHostOutput(ref this IncrementalGeneratorInitializationContext @this, IncrementalValuesProvider source, Action action) + { + _ = @this; + source.Node.RegisterOutput(new HostOutputNode(source.Node, action)); + } + + public static ImmutableArray<(string Key, string Value)> GetHostOutputs(this GeneratorRunResult runResult) => runResult.HostOutputs; + } + + internal readonly struct HostProductionContext + { + internal readonly ArrayBuilder<(string, string)> Outputs; + + internal HostProductionContext(ArrayBuilder<(string, string)> outputs) + { + Outputs = outputs; + } + + public void AddOutput(string name, string value) => Outputs.Add((name, value)); + } +} diff --git a/src/Tools/ExternalAccess/RazorCompiler/HostOutputNode.cs b/src/Tools/ExternalAccess/RazorCompiler/HostOutputNode.cs new file mode 100644 index 0000000000000..73380e5550dba --- /dev/null +++ b/src/Tools/ExternalAccess/RazorCompiler/HostOutputNode.cs @@ -0,0 +1,92 @@ +// 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.Diagnostics; +using System.Text; +using System.Threading; +using Microsoft.CodeAnalysis.PooledObjects; +using Roslyn.Utilities; +using TOutput = System.Collections.Immutable.ImmutableArray<(string, string)>; + +namespace Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler +{ + internal sealed class HostOutputNode : IIncrementalGeneratorOutputNode, IIncrementalGeneratorNode + { + private readonly IIncrementalGeneratorNode _source; + + private readonly Action _action; + + public HostOutputNode(IIncrementalGeneratorNode source, Action action) + { + _source = source; + _action = action; + } + + public IncrementalGeneratorOutputKind Kind => (IncrementalGeneratorOutputKind)0b100000; // several steps higher than IncrementalGeneratorOutputKind.Implementation + + public NodeStateTable UpdateStateTable(DriverStateTable.Builder graphState, NodeStateTable? previousTable, CancellationToken cancellationToken) + { + string stepName = "HostOutput"; + var sourceTable = graphState.GetLatestStateTableForNode(_source); + if (sourceTable.IsCached && previousTable is not null) + { + if (graphState.DriverState.TrackIncrementalSteps) + { + return previousTable.CreateCachedTableWithUpdatedSteps(sourceTable, stepName, EqualityComparer.Default); + } + return previousTable; + } + + var nodeTable = graphState.CreateTableBuilder(previousTable, stepName, EqualityComparer.Default); + foreach (var entry in sourceTable) + { + var inputs = nodeTable.TrackIncrementalSteps ? ImmutableArray.Create((entry.Step!, entry.OutputIndex)) : default; + if (entry.State == EntryState.Removed) + { + nodeTable.TryRemoveEntries(TimeSpan.Zero, inputs); + } + else if (entry.State != EntryState.Cached || !nodeTable.TryUseCachedEntries(TimeSpan.Zero, inputs)) + { + ArrayBuilder<(string, string)> output = ArrayBuilder<(string, string)>.GetInstance(); + HostProductionContext context = new HostProductionContext(output); + var stopwatch = SharedStopwatch.StartNew(); + _action(context, entry.Item, cancellationToken); + nodeTable.AddEntry(output.ToImmutableAndFree(), EntryState.Added, stopwatch.Elapsed, inputs, EntryState.Added); + } + } + + return nodeTable.ToImmutableAndFree(); + } + + public void AppendOutputs(IncrementalExecutionContext context, CancellationToken cancellationToken) + { + // get our own state table + Debug.Assert(context.TableBuilder is not null); + var table = context.TableBuilder!.GetLatestStateTableForNode(this); + + // add each non-removed entry to the context + foreach (var (list, state, _, _) in table) + { + if (state != EntryState.Removed) + { + context.HostOutputBuilder.AddRange(list); + } + } + + if (context.GeneratorRunStateBuilder.RecordingExecutedSteps) + { + context.GeneratorRunStateBuilder.RecordStepsFromOutputNodeUpdate(table); + } + } + + IIncrementalGeneratorNode IIncrementalGeneratorNode.WithComparer(IEqualityComparer comparer) => throw ExceptionUtilities.Unreachable(); + + public IIncrementalGeneratorNode WithTrackingName(string name) => throw ExceptionUtilities.Unreachable(); + + void IIncrementalGeneratorNode.RegisterOutput(IIncrementalGeneratorOutputNode output) => throw ExceptionUtilities.Unreachable(); + } +} diff --git a/src/Tools/ExternalAccess/RazorCompiler/InternalAPI.Shipped.txt b/src/Tools/ExternalAccess/RazorCompiler/InternalAPI.Shipped.txt new file mode 100644 index 0000000000000..7dc5c58110bfa --- /dev/null +++ b/src/Tools/ExternalAccess/RazorCompiler/InternalAPI.Shipped.txt @@ -0,0 +1 @@ +#nullable enable diff --git a/src/Tools/ExternalAccess/RazorCompiler/InternalAPI.Unshipped.txt b/src/Tools/ExternalAccess/RazorCompiler/InternalAPI.Unshipped.txt new file mode 100644 index 0000000000000..7c99629a815f4 --- /dev/null +++ b/src/Tools/ExternalAccess/RazorCompiler/InternalAPI.Unshipped.txt @@ -0,0 +1,15 @@ +#nullable enable +Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler.GeneratorExtensions +Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler.HostOutputNode +Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler.HostOutputNode.AppendOutputs(Microsoft.CodeAnalysis.IncrementalExecutionContext context, System.Threading.CancellationToken cancellationToken) -> void +Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler.HostOutputNode.HostOutputNode(Microsoft.CodeAnalysis.IIncrementalGeneratorNode! source, System.Action! action) -> void +Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler.HostOutputNode.Kind.get -> Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind +Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler.HostOutputNode.UpdateStateTable(Microsoft.CodeAnalysis.DriverStateTable.Builder! graphState, Microsoft.CodeAnalysis.NodeStateTable>? previousTable, System.Threading.CancellationToken cancellationToken) -> Microsoft.CodeAnalysis.NodeStateTable>! +Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler.HostOutputNode.WithTrackingName(string! name) -> Microsoft.CodeAnalysis.IIncrementalGeneratorNode>! +Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler.HostProductionContext +Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler.HostProductionContext.AddOutput(string! name, string! value) -> void +Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler.HostProductionContext.HostProductionContext() -> void +Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler.HostProductionContext.HostProductionContext(Microsoft.CodeAnalysis.PooledObjects.ArrayBuilder<(string!, string!)>! outputs) -> void +readonly Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler.HostProductionContext.Outputs -> Microsoft.CodeAnalysis.PooledObjects.ArrayBuilder<(string!, string!)>! +static Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler.GeneratorExtensions.GetHostOutputs(this Microsoft.CodeAnalysis.GeneratorRunResult runResult) -> System.Collections.Immutable.ImmutableArray<(string! Key, string! Value)> +static Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler.GeneratorExtensions.RegisterHostOutput(this ref Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext this, Microsoft.CodeAnalysis.IncrementalValuesProvider source, System.Action! action) -> void diff --git a/src/Tools/ExternalAccess/RazorCompiler/Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler.csproj b/src/Tools/ExternalAccess/RazorCompiler/Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler.csproj new file mode 100644 index 0000000000000..8868589e8e333 --- /dev/null +++ b/src/Tools/ExternalAccess/RazorCompiler/Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler.csproj @@ -0,0 +1,35 @@ + + + + + Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler + netstandard2.0 + + + true + Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler + + A supporting package for Razor source generator: + https://github.com/dotnet/razor + + + + + + + + + + + + + + + + + + + + diff --git a/src/Tools/ExternalAccess/RazorCompiler/PublicAPI.Shipped.txt b/src/Tools/ExternalAccess/RazorCompiler/PublicAPI.Shipped.txt new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/Tools/ExternalAccess/RazorCompiler/PublicAPI.Unshipped.txt b/src/Tools/ExternalAccess/RazorCompiler/PublicAPI.Unshipped.txt new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/Tools/IdeCoreBenchmarks/NavigateToBenchmarks.cs b/src/Tools/IdeCoreBenchmarks/NavigateToBenchmarks.cs index b778f4e9372b3..e3fb6376ad783 100644 --- a/src/Tools/IdeCoreBenchmarks/NavigateToBenchmarks.cs +++ b/src/Tools/IdeCoreBenchmarks/NavigateToBenchmarks.cs @@ -99,9 +99,9 @@ private void LoadSolution() // Force a storage instance to be created. This makes it simple to go examine it prior to any operations we // perform, including seeing how big the initial string table is. - var storageService = _workspace.Services.SolutionServices.GetPersistentStorageService(); - if (storageService == null) - throw new ArgumentException("Couldn't get storage service"); + //var storageService = _workspace.Services.SolutionServices.GetPersistentStorageService(); + //if (storageService == null) + // throw new ArgumentException("Couldn't get storage service"); } [IterationCleanup] @@ -111,6 +111,41 @@ public void IterationCleanup() _workspace = null; } + [Benchmark] + public async Task RunSerialParsing() + { + Console.WriteLine("start profiling now"); + Thread.Sleep(10000); + Console.WriteLine("Starting serial parsing."); + var start = DateTime.Now; + var roots = new List(); + foreach (var project in _workspace.CurrentSolution.Projects) + { + foreach (var document in project.Documents) + { + // await WalkTree(document); + roots.Add(await document.GetSyntaxRootAsync()); + } + } + + Console.WriteLine("Serial: " + (DateTime.Now - start)); + Console.WriteLine($"{nameof(DocumentState.TestAccessor.TryReuseSyntaxTree)} - {DocumentState.TestAccessor.TryReuseSyntaxTree}"); + Console.WriteLine($"{nameof(DocumentState.TestAccessor.CouldReuseBecauseOfEqualPPNames)} - {DocumentState.TestAccessor.CouldReuseBecauseOfEqualPPNames}"); + Console.WriteLine($"{nameof(DocumentState.TestAccessor.CouldReuseBecauseOfNoDirectives)} - {DocumentState.TestAccessor.CouldReuseBecauseOfNoDirectives}"); + Console.WriteLine($"{nameof(DocumentState.TestAccessor.CouldReuseBecauseOfNoPPDirectives)} - {DocumentState.TestAccessor.CouldReuseBecauseOfNoPPDirectives}"); + Console.WriteLine($"{nameof(DocumentState.TestAccessor.CouldNotReuse)} - {DocumentState.TestAccessor.CouldNotReuse}"); + + for (var i = 0; i < 10; i++) + { + GC.Collect(0, GCCollectionMode.Forced, blocking: true); + GC.Collect(1, GCCollectionMode.Forced, blocking: true); + GC.Collect(2, GCCollectionMode.Forced, blocking: true); + } + + Console.ReadLine(); + GC.KeepAlive(roots); + } + // [Benchmark] public async Task RunSerialIndexing() { @@ -151,7 +186,7 @@ public async Task RunProjectParallelIndexing() Console.ReadLine(); } - [Benchmark] + // [Benchmark] public async Task RunFullParallelIndexing() { Console.WriteLine("Attach now"); diff --git a/src/Tools/Source/RunTests/TestRunner.cs b/src/Tools/Source/RunTests/TestRunner.cs index dd13345868258..573174594f74a 100644 --- a/src/Tools/Source/RunTests/TestRunner.cs +++ b/src/Tools/Source/RunTests/TestRunner.cs @@ -127,7 +127,7 @@ internal async Task RunAllOnHelixAsync(ImmutableArray ConsoleUtil.WriteLine(e.Data), + onOutputDataReceived: (e) => { Debug.Assert(e.Data is not null); ConsoleUtil.WriteLine(e.Data); }, cancellationToken: cancellationToken); var result = await process.Result; diff --git a/src/VisualStudio/CSharp/Impl/CSharpPackage.cs b/src/VisualStudio/CSharp/Impl/CSharpPackage.cs index 06a800c402b74..6e9feeaa919bc 100644 --- a/src/VisualStudio/CSharp/Impl/CSharpPackage.cs +++ b/src/VisualStudio/CSharp/Impl/CSharpPackage.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.LanguageServices.CSharp.ObjectBrowser; using Microsoft.VisualStudio.LanguageServices.CSharp.ProjectSystemShim; using Microsoft.VisualStudio.LanguageServices.CSharp.ProjectSystemShim.Interop; @@ -126,8 +127,7 @@ protected override object GetAutomationObject(string name) { if (name == "CSharp-Specific") { - var workspace = this.ComponentModel.GetService(); - return new Options.AutomationObject(workspace); + return new Options.AutomationObject(ComponentModel.GetService()); } return base.GetAutomationObject(name); diff --git a/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsLanguageServiceFactory.cs b/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsLanguageServiceFactory.cs index b4ffb45e574f0..e1a3a7c1078e8 100644 --- a/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsLanguageServiceFactory.cs +++ b/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsLanguageServiceFactory.cs @@ -9,22 +9,26 @@ using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; namespace Microsoft.VisualStudio.LanguageServices.CSharp.EditorConfigSettings.DataProvider.CodeStyle { [ExportLanguageServiceFactory(typeof(ILanguageSettingsProviderFactory), LanguageNames.CSharp), Shared] - internal class CSharpCodeStyleSettingsLanguageServiceFactory : ILanguageServiceFactory + internal sealed class CSharpCodeStyleSettingsLanguageServiceFactory : ILanguageServiceFactory { + private readonly IGlobalOptionService _globalOptions; + [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpCodeStyleSettingsLanguageServiceFactory() + public CSharpCodeStyleSettingsLanguageServiceFactory(IGlobalOptionService globalOptions) { + _globalOptions = globalOptions; } public ILanguageService CreateLanguageService(HostLanguageServices languageServices) { var workspace = languageServices.WorkspaceServices.Workspace; - return new CSharpCodeStyleSettingsProviderFactory(workspace); + return new CSharpCodeStyleSettingsProviderFactory(workspace, _globalOptions); } } } diff --git a/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProvider.cs b/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProvider.cs index f2f7be7e36ebc..8a157cad4ce29 100644 --- a/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProvider.cs +++ b/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProvider.cs @@ -18,8 +18,8 @@ namespace Microsoft.VisualStudio.LanguageServices.CSharp.EditorConfigSettings.Da { internal class CSharpCodeStyleSettingsProvider : SettingsProviderBase { - public CSharpCodeStyleSettingsProvider(string fileName, OptionUpdater settingsUpdater, Workspace workspace) - : base(fileName, settingsUpdater, workspace) + public CSharpCodeStyleSettingsProvider(string fileName, OptionUpdater settingsUpdater, Workspace workspace, IGlobalOptionService globalOptions) + : base(fileName, settingsUpdater, workspace, globalOptions) { Update(); } diff --git a/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProviderFactory.cs b/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProviderFactory.cs index 1af8c72ade4d0..f563b8eff07df 100644 --- a/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProviderFactory.cs +++ b/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProviderFactory.cs @@ -6,16 +6,22 @@ using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider; using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Options; namespace Microsoft.VisualStudio.LanguageServices.CSharp.EditorConfigSettings.DataProvider.CodeStyle { - internal class CSharpCodeStyleSettingsProviderFactory : ILanguageSettingsProviderFactory + internal sealed class CSharpCodeStyleSettingsProviderFactory : ILanguageSettingsProviderFactory { private readonly Workspace _workspace; + private readonly IGlobalOptionService _globalOptions; - public CSharpCodeStyleSettingsProviderFactory(Workspace workspace) => _workspace = workspace; + public CSharpCodeStyleSettingsProviderFactory(Workspace workspace, IGlobalOptionService globalOptions) + { + _workspace = workspace; + _globalOptions = globalOptions; + } public ISettingsProvider GetForFile(string filePath) - => new CSharpCodeStyleSettingsProvider(filePath, new OptionUpdater(_workspace, filePath), _workspace); + => new CSharpCodeStyleSettingsProvider(filePath, new OptionUpdater(_workspace, filePath), _workspace, _globalOptions); } } diff --git a/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/Whitespace/CSharpWhitespaceSettingsLanguageServiceFactory.cs b/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/Whitespace/CSharpWhitespaceSettingsLanguageServiceFactory.cs index b167e10884867..c53c3d2cfa706 100644 --- a/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/Whitespace/CSharpWhitespaceSettingsLanguageServiceFactory.cs +++ b/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/Whitespace/CSharpWhitespaceSettingsLanguageServiceFactory.cs @@ -9,22 +9,26 @@ using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; namespace Microsoft.VisualStudio.LanguageServices.CSharp.EditorConfigSettings.DataProvider.Whitespace { [ExportLanguageServiceFactory(typeof(ILanguageSettingsProviderFactory), LanguageNames.CSharp), Shared] - internal class CSharpWhitespaceSettingsLanguageServiceFactory : ILanguageServiceFactory + internal sealed class CSharpWhitespaceSettingsLanguageServiceFactory : ILanguageServiceFactory { + private readonly IGlobalOptionService _globalOptions; + [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpWhitespaceSettingsLanguageServiceFactory() + public CSharpWhitespaceSettingsLanguageServiceFactory(IGlobalOptionService globalOptions) { + _globalOptions = globalOptions; } public ILanguageService CreateLanguageService(HostLanguageServices languageServices) { var workspace = languageServices.WorkspaceServices.Workspace; - return new CSharpWhitespaceSettingsProviderFactory(workspace); + return new CSharpWhitespaceSettingsProviderFactory(workspace, _globalOptions); } } } diff --git a/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/Whitespace/CSharpWhitespaceSettingsProvider.cs b/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/Whitespace/CSharpWhitespaceSettingsProvider.cs index 32efd564df097..ea62715312a13 100644 --- a/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/Whitespace/CSharpWhitespaceSettingsProvider.cs +++ b/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/Whitespace/CSharpWhitespaceSettingsProvider.cs @@ -23,8 +23,8 @@ internal sealed class CSharpWhitespaceSettingsProvider : SettingsProviderBase s_spaceBetweenParenthesesConversions = new(v => (int)v, v => (SpacePlacementWithinParentheses)v); private static readonly Conversions s_newLinesForBracesConversions = new(v => (int)v, v => (NewLineBeforeOpenBracePlacement)v); - public CSharpWhitespaceSettingsProvider(string filePath, OptionUpdater updaterService, Workspace workspace) - : base(filePath, updaterService, workspace) + public CSharpWhitespaceSettingsProvider(string filePath, OptionUpdater updaterService, Workspace workspace, IGlobalOptionService globalOptions) + : base(filePath, updaterService, workspace, globalOptions) { Update(); } diff --git a/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/Whitespace/CSharpWhitespaceSettingsProviderFactory.cs b/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/Whitespace/CSharpWhitespaceSettingsProviderFactory.cs index eaaff2b095d09..ac7584295a258 100644 --- a/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/Whitespace/CSharpWhitespaceSettingsProviderFactory.cs +++ b/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/Whitespace/CSharpWhitespaceSettingsProviderFactory.cs @@ -6,22 +6,25 @@ using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider; using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Options; namespace Microsoft.VisualStudio.LanguageServices.CSharp.EditorConfigSettings.DataProvider.Whitespace { - internal class CSharpWhitespaceSettingsProviderFactory : ILanguageSettingsProviderFactory + internal sealed class CSharpWhitespaceSettingsProviderFactory : ILanguageSettingsProviderFactory { private readonly Workspace _workspace; + private readonly IGlobalOptionService _globalOptions; - public CSharpWhitespaceSettingsProviderFactory(Workspace workspace) + public CSharpWhitespaceSettingsProviderFactory(Workspace workspace, IGlobalOptionService globalOptions) { _workspace = workspace; + _globalOptions = globalOptions; } public ISettingsProvider GetForFile(string filePath) { var updaterService = new OptionUpdater(_workspace, filePath); - return new CSharpWhitespaceSettingsProvider(filePath, updaterService, _workspace); + return new CSharpWhitespaceSettingsProvider(filePath, updaterService, _workspace, _globalOptions); } } } diff --git a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs index e867faee01b0b..6006431636ec6 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs +++ b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs @@ -130,7 +130,7 @@ public AdvancedOptionPageControl(OptionStore optionStore, IComponentModel compon // Editor Help BindToOption(ShowRemarksInQuickInfo, QuickInfoOptionsStorage.ShowRemarksInQuickInfo, LanguageNames.CSharp); BindToOption(RenameTrackingPreview, FeatureOnOffOptions.RenameTrackingPreview, LanguageNames.CSharp); - BindToOption(Split_string_literals_on_enter, SplitStringLiteralOptions.Enabled, LanguageNames.CSharp); + BindToOption(Split_string_literals_on_enter, SplitStringLiteralOptions.Enabled); BindToOption(Fix_text_pasted_into_string_literals_experimental, FeatureOnOffOptions.AutomaticallyFixStringContentsOnPaste, LanguageNames.CSharp); BindToOption(Report_invalid_placeholders_in_string_dot_format_calls, IdeAnalyzerOptionsStorage.ReportInvalidPlaceholdersInStringDotFormatCalls, LanguageNames.CSharp); BindToOption(Underline_reassigned_variables, ClassificationOptionsStorage.ClassifyReassignedVariables, LanguageNames.CSharp); diff --git a/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.Formatting.cs b/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.Formatting.cs index 3eb0b9da1ba1d..177fb135cbd71 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.Formatting.cs +++ b/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.Formatting.cs @@ -59,56 +59,56 @@ public int NewLines_AnonymousTypeInitializer_EachMember public int NewLines_Braces_AnonymousMethod { - get { return GetBooleanOption(CSharpFormattingOptions2.NewLinesForBracesInAnonymousMethods); } - set { SetBooleanOption(CSharpFormattingOptions2.NewLinesForBracesInAnonymousMethods, value); } + get { return GetBooleanOption(CSharpFormattingOptions2.NewLineBeforeOpenBrace, NewLineBeforeOpenBracePlacement.AnonymousMethods); } + set { SetBooleanOption(CSharpFormattingOptions2.NewLineBeforeOpenBrace, NewLineBeforeOpenBracePlacement.AnonymousMethods, value); } } public int NewLines_Braces_AnonymousTypeInitializer { - get { return GetBooleanOption(CSharpFormattingOptions2.NewLinesForBracesInAnonymousTypes); } - set { SetBooleanOption(CSharpFormattingOptions2.NewLinesForBracesInAnonymousTypes, value); } + get { return GetBooleanOption(CSharpFormattingOptions2.NewLineBeforeOpenBrace, NewLineBeforeOpenBracePlacement.AnonymousTypes); } + set { SetBooleanOption(CSharpFormattingOptions2.NewLineBeforeOpenBrace, NewLineBeforeOpenBracePlacement.AnonymousTypes, value); } } public int NewLines_Braces_ControlFlow { - get { return GetBooleanOption(CSharpFormattingOptions2.NewLinesForBracesInControlBlocks); } - set { SetBooleanOption(CSharpFormattingOptions2.NewLinesForBracesInControlBlocks, value); } + get { return GetBooleanOption(CSharpFormattingOptions2.NewLineBeforeOpenBrace, NewLineBeforeOpenBracePlacement.ControlBlocks); } + set { SetBooleanOption(CSharpFormattingOptions2.NewLineBeforeOpenBrace, NewLineBeforeOpenBracePlacement.ControlBlocks, value); } } public int NewLines_Braces_LambdaExpressionBody { - get { return GetBooleanOption(CSharpFormattingOptions2.NewLinesForBracesInLambdaExpressionBody); } - set { SetBooleanOption(CSharpFormattingOptions2.NewLinesForBracesInLambdaExpressionBody, value); } + get { return GetBooleanOption(CSharpFormattingOptions2.NewLineBeforeOpenBrace, NewLineBeforeOpenBracePlacement.LambdaExpressionBody); } + set { SetBooleanOption(CSharpFormattingOptions2.NewLineBeforeOpenBrace, NewLineBeforeOpenBracePlacement.LambdaExpressionBody, value); } } public int NewLines_Braces_Method { - get { return GetBooleanOption(CSharpFormattingOptions2.NewLinesForBracesInMethods); } - set { SetBooleanOption(CSharpFormattingOptions2.NewLinesForBracesInMethods, value); } + get { return GetBooleanOption(CSharpFormattingOptions2.NewLineBeforeOpenBrace, NewLineBeforeOpenBracePlacement.Methods); } + set { SetBooleanOption(CSharpFormattingOptions2.NewLineBeforeOpenBrace, NewLineBeforeOpenBracePlacement.Methods, value); } } public int NewLines_Braces_Property { - get { return GetBooleanOption(CSharpFormattingOptions2.NewLinesForBracesInProperties); } - set { SetBooleanOption(CSharpFormattingOptions2.NewLinesForBracesInProperties, value); } + get { return GetBooleanOption(CSharpFormattingOptions2.NewLineBeforeOpenBrace, NewLineBeforeOpenBracePlacement.Properties); } + set { SetBooleanOption(CSharpFormattingOptions2.NewLineBeforeOpenBrace, NewLineBeforeOpenBracePlacement.Properties, value); } } public int NewLines_Braces_Accessor { - get { return GetBooleanOption(CSharpFormattingOptions2.NewLinesForBracesInAccessors); } - set { SetBooleanOption(CSharpFormattingOptions2.NewLinesForBracesInAccessors, value); } + get { return GetBooleanOption(CSharpFormattingOptions2.NewLineBeforeOpenBrace, NewLineBeforeOpenBracePlacement.Accessors); } + set { SetBooleanOption(CSharpFormattingOptions2.NewLineBeforeOpenBrace, NewLineBeforeOpenBracePlacement.Accessors, value); } } public int NewLines_Braces_ObjectInitializer { - get { return GetBooleanOption(CSharpFormattingOptions2.NewLinesForBracesInObjectCollectionArrayInitializers); } - set { SetBooleanOption(CSharpFormattingOptions2.NewLinesForBracesInObjectCollectionArrayInitializers, value); } + get { return GetBooleanOption(CSharpFormattingOptions2.NewLineBeforeOpenBrace, NewLineBeforeOpenBracePlacement.ObjectCollectionArrayInitializers); } + set { SetBooleanOption(CSharpFormattingOptions2.NewLineBeforeOpenBrace, NewLineBeforeOpenBracePlacement.ObjectCollectionArrayInitializers, value); } } public int NewLines_Braces_Type { - get { return GetBooleanOption(CSharpFormattingOptions2.NewLinesForBracesInTypes); } - set { SetBooleanOption(CSharpFormattingOptions2.NewLinesForBracesInTypes, value); } + get { return GetBooleanOption(CSharpFormattingOptions2.NewLineBeforeOpenBrace, NewLineBeforeOpenBracePlacement.Types); } + set { SetBooleanOption(CSharpFormattingOptions2.NewLineBeforeOpenBrace, NewLineBeforeOpenBracePlacement.Types, value); } } public int NewLines_Keywords_Catch @@ -245,14 +245,20 @@ public int Space_InControlFlowConstruct public int Space_WithinCastParentheses { - get { return GetBooleanOption(CSharpFormattingOptions2.SpaceWithinCastParentheses); } - set { SetBooleanOption(CSharpFormattingOptions2.SpaceWithinCastParentheses, value); } + get { return GetBooleanOption(CSharpFormattingOptions2.SpaceBetweenParentheses, SpacePlacementWithinParentheses.TypeCasts); } + set { SetBooleanOption(CSharpFormattingOptions2.SpaceBetweenParentheses, SpacePlacementWithinParentheses.TypeCasts, value); } } public int Space_WithinExpressionParentheses { - get { return GetBooleanOption(CSharpFormattingOptions2.SpaceWithinExpressionParentheses); } - set { SetBooleanOption(CSharpFormattingOptions2.SpaceWithinExpressionParentheses, value); } + get { return GetBooleanOption(CSharpFormattingOptions2.SpaceBetweenParentheses, SpacePlacementWithinParentheses.Expressions); } + set { SetBooleanOption(CSharpFormattingOptions2.SpaceBetweenParentheses, SpacePlacementWithinParentheses.Expressions, value); } + } + + public int Space_WithinOtherParentheses + { + get { return GetBooleanOption(CSharpFormattingOptions2.SpaceBetweenParentheses, SpacePlacementWithinParentheses.ControlFlowStatements); } + set { SetBooleanOption(CSharpFormattingOptions2.SpaceBetweenParentheses, SpacePlacementWithinParentheses.ControlFlowStatements, value); } } public int Space_WithinMethodCallParentheses @@ -267,12 +273,6 @@ public int Space_WithinMethodDeclarationParentheses set { SetBooleanOption(CSharpFormattingOptions2.SpaceWithinMethodDeclarationParenthesis, value); } } - public int Space_WithinOtherParentheses - { - get { return GetBooleanOption(CSharpFormattingOptions2.SpaceWithinOtherParentheses); } - set { SetBooleanOption(CSharpFormattingOptions2.SpaceWithinOtherParentheses, value); } - } - public int Space_WithinSquares { get { return GetBooleanOption(CSharpFormattingOptions2.SpaceWithinSquareBrackets); } diff --git a/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.cs b/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.cs index c966bf97d6a83..4320c664485ad 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.cs +++ b/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.cs @@ -4,6 +4,7 @@ using System.Runtime.InteropServices; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Formatting; using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.LanguageServices.Implementation.Options; @@ -12,20 +13,33 @@ namespace Microsoft.VisualStudio.LanguageServices.CSharp.Options [ComVisible(true)] public partial class AutomationObject : AbstractAutomationObject { - internal AutomationObject(Workspace workspace) : base(workspace, LanguageNames.CSharp) + internal AutomationObject(ILegacyGlobalOptionService legacyGlobalOptions) + : base(legacyGlobalOptions, LanguageNames.CSharp) { } - private int GetBooleanOption(Option2 key) - => GetOption(key) ? 1 : 0; + private int GetBooleanOption(Option2 option) + => GetOption(option) ? 1 : 0; - private int GetBooleanOption(PerLanguageOption2 key) - => GetOption(key) ? 1 : 0; + private int GetBooleanOption(PerLanguageOption2 option) + => GetOption(option) ? 1 : 0; - private void SetBooleanOption(Option2 key, int value) - => SetOption(key, value != 0); + private int GetBooleanOption(Option2 option, NewLineBeforeOpenBracePlacement flag) + => GetOption(option).HasFlag(flag) ? 1 : 0; - private void SetBooleanOption(PerLanguageOption2 key, int value) - => SetOption(key, value != 0); + private int GetBooleanOption(Option2 option, SpacePlacementWithinParentheses flag) + => GetOption(option).HasFlag(flag) ? 1 : 0; + + private void SetBooleanOption(Option2 option, int value) + => SetOption(option, value != 0); + + private void SetBooleanOption(PerLanguageOption2 option, int value) + => SetOption(option, value != 0); + + private void SetBooleanOption(Option2 option, NewLineBeforeOpenBracePlacement flag, int value) + => SetOption(option, GetOption(option).WithFlagValue(flag, value != 0)); + + private void SetBooleanOption(Option2 option, SpacePlacementWithinParentheses flag, int value) + => SetOption(option, GetOption(option).WithFlagValue(flag, value != 0)); } } diff --git a/src/VisualStudio/CSharp/Impl/Options/CSharpVisualStudioOptionStorageReadFallbacks.cs b/src/VisualStudio/CSharp/Impl/Options/CSharpVisualStudioOptionStorageReadFallbacks.cs new file mode 100644 index 0000000000000..809b30bed6ead --- /dev/null +++ b/src/VisualStudio/CSharp/Impl/Options/CSharpVisualStudioOptionStorageReadFallbacks.cs @@ -0,0 +1,83 @@ +// 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.Collections.Generic; +using System.Composition; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.CSharp.Formatting; +using Microsoft.VisualStudio.LanguageServices.Options; + +namespace Microsoft.VisualStudio.LanguageServices.CSharp; + +internal static class CSharpVisualStudioOptionStorageReadFallbacks +{ + [ExportVisualStudioStorageReadFallback("csharp_space_between_parentheses"), Shared] + internal sealed class SpaceBetweenFarentheses : IVisualStudioStorageReadFallback + { + private static ImmutableArray<(string key, int flag)> s_storages => ImmutableArray.Create( + ("TextEditor.CSharp.Specific.SpaceWithinExpressionParentheses", (int)SpacePlacementWithinParentheses.Expressions), + ("TextEditor.CSharp.Specific.SpaceWithinCastParentheses", (int)SpacePlacementWithinParentheses.Expressions), + ("TextEditor.CSharp.Specific.SpaceWithinOtherParentheses", (int)SpacePlacementWithinParentheses.ControlFlowStatements)); + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public SpaceBetweenFarentheses() + { + } + + public Optional TryRead(string? language, TryReadValueDelegate readValue) + => TryReadFlags(s_storages, readValue, out var intValue) ? (SpacePlacementWithinParentheses)intValue : default; + } + + [ExportVisualStudioStorageReadFallback("csharp_new_line_before_open_brace"), Shared] + internal sealed class NewLinesForBraces : IVisualStudioStorageReadFallback + { + private static ImmutableArray<(string key, int flag)> s_storages => ImmutableArray.Create( + ("TextEditor.CSharp.Specific.NewLinesForBracesInTypes", (int)NewLineBeforeOpenBracePlacement.Types), + ("TextEditor.CSharp.Specific.NewLinesForBracesInAnonymousTypes", (int)NewLineBeforeOpenBracePlacement.AnonymousTypes), + ("TextEditor.CSharp.Specific.NewLinesForBracesInObjectCollectionArrayInitializers", (int)NewLineBeforeOpenBracePlacement.ObjectCollectionArrayInitializers), + ("TextEditor.CSharp.Specific.NewLinesForBracesInProperties", (int)NewLineBeforeOpenBracePlacement.Properties), + ("TextEditor.CSharp.Specific.NewLinesForBracesInMethods", (int)NewLineBeforeOpenBracePlacement.Methods), + ("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)); + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public NewLinesForBraces() + { + } + + public Optional TryRead(string? language, TryReadValueDelegate readValue) + => TryReadFlags(s_storages, readValue, out var intValue) ? (NewLineBeforeOpenBracePlacement)intValue : default; + } + + private static bool TryReadFlags(ImmutableArray<(string key, int flag)> storages, TryReadValueDelegate read, out int result) + { + var hasAnyFlag = false; + result = 0; + foreach (var (key, flag) in storages) + { + var value = read(key, typeof(bool)); + if (value.HasValue) + { + if ((bool)value.Value!) + { + result |= flag; + } + + hasAnyFlag = true; + } + } + + return hasAnyFlag; + } +} diff --git a/src/VisualStudio/CSharp/Impl/Options/Formatting/CodeStylePage.cs b/src/VisualStudio/CSharp/Impl/Options/Formatting/CodeStylePage.cs index 618c2c4d5ec78..02b5e27239acc 100644 --- a/src/VisualStudio/CSharp/Impl/Options/Formatting/CodeStylePage.cs +++ b/src/VisualStudio/CSharp/Impl/Options/Formatting/CodeStylePage.cs @@ -30,18 +30,18 @@ protected override AbstractOptionPageControl CreateOptionPage(IServiceProvider s LanguageNames.CSharp); } - private static ImmutableArray<(string feature, ImmutableArray options)> GetEditorConfigOptions() + private static ImmutableArray<(string feature, ImmutableArray options)> GetEditorConfigOptions() { - var builder = ArrayBuilder<(string, ImmutableArray)>.GetInstance(); + var builder = ArrayBuilder<(string, ImmutableArray)>.GetInstance(); builder.AddRange(GridOptionPreviewControl.GetLanguageAgnosticEditorConfigOptions()); - builder.Add((CSharpVSResources.CSharp_Coding_Conventions, CSharpCodeStyleOptions.AllOptions.As())); - builder.Add((CSharpVSResources.CSharp_Formatting_Rules, CSharpFormattingOptions2.AllOptions.As())); + builder.Add((CSharpVSResources.CSharp_Coding_Conventions, CSharpCodeStyleOptions.AllOptions)); + builder.Add((CSharpVSResources.CSharp_Formatting_Rules, CSharpFormattingOptions2.AllOptions)); return builder.ToImmutableAndFree(); } internal readonly struct TestAccessor { - internal static ImmutableArray<(string feature, ImmutableArray options)> GetEditorConfigOptions() + internal static ImmutableArray<(string feature, ImmutableArray options)> GetEditorConfigOptions() => CodeStylePage.GetEditorConfigOptions(); } } diff --git a/src/VisualStudio/CSharp/Impl/Options/Formatting/NewLinesViewModel.cs b/src/VisualStudio/CSharp/Impl/Options/Formatting/NewLinesViewModel.cs index ea773717872e0..427027de4d222 100644 --- a/src/VisualStudio/CSharp/Impl/Options/Formatting/NewLinesViewModel.cs +++ b/src/VisualStudio/CSharp/Impl/Options/Formatting/NewLinesViewModel.cs @@ -5,8 +5,10 @@ #nullable disable using System; +using System.Runtime.CompilerServices; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Formatting; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.LanguageServices.Implementation.Options; @@ -17,6 +19,8 @@ namespace Microsoft.VisualStudio.LanguageServices.CSharp.Options.Formatting /// internal class NewLinesViewModel : AbstractOptionPreviewViewModel { + private static readonly Conversions s_newLinesForBracesConversions = new(v => (int)v, v => (NewLineBeforeOpenBracePlacement)v); + private const string s_previewText = @"//[ class C { } @@ -202,15 +206,17 @@ class B { public NewLinesViewModel(OptionStore optionStore, IServiceProvider serviceProvider) : base(optionStore, serviceProvider, LanguageNames.CSharp) { Items.Add(new HeaderItemViewModel() { Header = CSharpVSResources.New_line_options_for_braces }); - Items.Add(new CheckBoxOptionViewModel(CSharpFormattingOptions2.NewLinesForBracesInTypes, CSharpVSResources.Place_open_brace_on_new_line_for_types, s_previewText, this, optionStore)); - Items.Add(new CheckBoxOptionViewModel(CSharpFormattingOptions2.NewLinesForBracesInMethods, CSharpVSResources.Place_open_brace_on_new_line_for_methods_local_functions, s_methodPreview, this, optionStore)); - Items.Add(new CheckBoxOptionViewModel(CSharpFormattingOptions2.NewLinesForBracesInProperties, CSharpVSResources.Place_open_brace_on_new_line_for_properties_indexers_and_events, s_propertyPreview, this, optionStore)); - Items.Add(new CheckBoxOptionViewModel(CSharpFormattingOptions2.NewLinesForBracesInAccessors, CSharpVSResources.Place_open_brace_on_new_line_for_property_indexer_and_event_accessors, s_propertyPreview, this, optionStore)); - Items.Add(new CheckBoxOptionViewModel(CSharpFormattingOptions2.NewLinesForBracesInAnonymousMethods, CSharpVSResources.Place_open_brace_on_new_line_for_anonymous_methods, s_anonymousMethodPreview, this, optionStore)); - Items.Add(new CheckBoxOptionViewModel(CSharpFormattingOptions2.NewLinesForBracesInControlBlocks, CSharpVSResources.Place_open_brace_on_new_line_for_control_blocks, s_forBlockPreview, this, optionStore)); - Items.Add(new CheckBoxOptionViewModel(CSharpFormattingOptions2.NewLinesForBracesInAnonymousTypes, CSharpVSResources.Place_open_brace_on_new_line_for_anonymous_types, s_anonymousTypePreview, this, optionStore)); - Items.Add(new CheckBoxOptionViewModel(CSharpFormattingOptions2.NewLinesForBracesInObjectCollectionArrayInitializers, CSharpVSResources.Place_open_brace_on_new_line_for_object_collection_array_and_with_initializers, s_InitializerPreviewTrue, s_InitializerPreviewFalse, this, optionStore)); - Items.Add(new CheckBoxOptionViewModel(CSharpFormattingOptions2.NewLinesForBracesInLambdaExpressionBody, CSharpVSResources.Place_open_brace_on_new_line_for_lambda_expression, s_lambdaPreview, this, optionStore)); + + var newLineBeforeOpenBraceValue = new StrongBox(); + Items.Add(new CheckBoxEnumFlagsOptionViewModel(CSharpFormattingOptions2.NewLineBeforeOpenBrace, (int)NewLineBeforeOpenBracePlacement.Types, CSharpVSResources.Place_open_brace_on_new_line_for_types, s_previewText, this, optionStore, newLineBeforeOpenBraceValue, s_newLinesForBracesConversions)); + Items.Add(new CheckBoxEnumFlagsOptionViewModel(CSharpFormattingOptions2.NewLineBeforeOpenBrace, (int)NewLineBeforeOpenBracePlacement.Methods, CSharpVSResources.Place_open_brace_on_new_line_for_methods_local_functions, s_methodPreview, this, optionStore, newLineBeforeOpenBraceValue, s_newLinesForBracesConversions)); + Items.Add(new CheckBoxEnumFlagsOptionViewModel(CSharpFormattingOptions2.NewLineBeforeOpenBrace, (int)NewLineBeforeOpenBracePlacement.Properties, CSharpVSResources.Place_open_brace_on_new_line_for_properties_indexers_and_events, s_propertyPreview, this, optionStore, newLineBeforeOpenBraceValue, s_newLinesForBracesConversions)); + Items.Add(new CheckBoxEnumFlagsOptionViewModel(CSharpFormattingOptions2.NewLineBeforeOpenBrace, (int)NewLineBeforeOpenBracePlacement.Accessors, CSharpVSResources.Place_open_brace_on_new_line_for_property_indexer_and_event_accessors, s_propertyPreview, this, optionStore, newLineBeforeOpenBraceValue, s_newLinesForBracesConversions)); + Items.Add(new CheckBoxEnumFlagsOptionViewModel(CSharpFormattingOptions2.NewLineBeforeOpenBrace, (int)NewLineBeforeOpenBracePlacement.AnonymousMethods, CSharpVSResources.Place_open_brace_on_new_line_for_anonymous_methods, s_anonymousMethodPreview, this, optionStore, newLineBeforeOpenBraceValue, s_newLinesForBracesConversions)); + Items.Add(new CheckBoxEnumFlagsOptionViewModel(CSharpFormattingOptions2.NewLineBeforeOpenBrace, (int)NewLineBeforeOpenBracePlacement.ControlBlocks, CSharpVSResources.Place_open_brace_on_new_line_for_control_blocks, s_forBlockPreview, this, optionStore, newLineBeforeOpenBraceValue, s_newLinesForBracesConversions)); + Items.Add(new CheckBoxEnumFlagsOptionViewModel(CSharpFormattingOptions2.NewLineBeforeOpenBrace, (int)NewLineBeforeOpenBracePlacement.AnonymousTypes, CSharpVSResources.Place_open_brace_on_new_line_for_anonymous_types, s_anonymousTypePreview, this, optionStore, newLineBeforeOpenBraceValue, s_newLinesForBracesConversions)); + Items.Add(new CheckBoxEnumFlagsOptionViewModel(CSharpFormattingOptions2.NewLineBeforeOpenBrace, (int)NewLineBeforeOpenBracePlacement.ObjectCollectionArrayInitializers, CSharpVSResources.Place_open_brace_on_new_line_for_object_collection_array_and_with_initializers, s_InitializerPreviewTrue, s_InitializerPreviewFalse, this, optionStore, newLineBeforeOpenBraceValue, s_newLinesForBracesConversions)); + Items.Add(new CheckBoxEnumFlagsOptionViewModel(CSharpFormattingOptions2.NewLineBeforeOpenBrace, (int)NewLineBeforeOpenBracePlacement.LambdaExpressionBody, CSharpVSResources.Place_open_brace_on_new_line_for_lambda_expression, s_lambdaPreview, this, optionStore, newLineBeforeOpenBraceValue, s_newLinesForBracesConversions)); Items.Add(new HeaderItemViewModel() { Header = CSharpVSResources.New_line_options_for_keywords }); diff --git a/src/VisualStudio/CSharp/Impl/Options/Formatting/SpacingViewModel.cs b/src/VisualStudio/CSharp/Impl/Options/Formatting/SpacingViewModel.cs index 591c8b2cf9f54..4cd0a2759b781 100644 --- a/src/VisualStudio/CSharp/Impl/Options/Formatting/SpacingViewModel.cs +++ b/src/VisualStudio/CSharp/Impl/Options/Formatting/SpacingViewModel.cs @@ -5,10 +5,12 @@ #nullable disable using System; +using System.Runtime.CompilerServices; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Formatting; using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.LanguageServices.Implementation.Options; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; namespace Microsoft.VisualStudio.LanguageServices.CSharp.Options.Formatting { @@ -17,6 +19,8 @@ namespace Microsoft.VisualStudio.LanguageServices.CSharp.Options.Formatting /// internal class SpacingViewModel : AbstractOptionPreviewViewModel { + private static readonly Conversions s_spaceBetweenParenthesesConversions = new(v => (int)v, v => (SpacePlacementWithinParentheses)v); + private const string s_methodPreview = @" class C { //[ @@ -119,9 +123,12 @@ public SpacingViewModel(OptionStore optionStore, IServiceProvider serviceProvide Items.Add(new HeaderItemViewModel() { Header = CSharpVSResources.Set_other_spacing_options }); Items.Add(new CheckBoxOptionViewModel(CSharpFormattingOptions2.SpaceAfterControlFlowStatementKeyword, CSharpVSResources.Insert_space_after_keywords_in_control_flow_statements, s_forDelimiterPreview, this, optionStore)); - Items.Add(new CheckBoxOptionViewModel(CSharpFormattingOptions2.SpaceWithinExpressionParentheses, CSharpVSResources.Insert_space_within_parentheses_of_expressions, s_expressionPreview, this, optionStore)); - Items.Add(new CheckBoxOptionViewModel(CSharpFormattingOptions2.SpaceWithinCastParentheses, CSharpVSResources.Insert_space_within_parentheses_of_type_casts, s_castPreview, this, optionStore)); - Items.Add(new CheckBoxOptionViewModel(CSharpFormattingOptions2.SpaceWithinOtherParentheses, CSharpVSResources.Insert_spaces_within_parentheses_of_control_flow_statements, s_forDelimiterPreview, this, optionStore)); + + var spaceBetweenParenthesesStorage = new StrongBox(); + Items.Add(new CheckBoxEnumFlagsOptionViewModel(CSharpFormattingOptions2.SpaceBetweenParentheses, (int)SpacePlacementWithinParentheses.Expressions, CSharpVSResources.Insert_space_within_parentheses_of_expressions, s_expressionPreview, this, optionStore, spaceBetweenParenthesesStorage, s_spaceBetweenParenthesesConversions)); + Items.Add(new CheckBoxEnumFlagsOptionViewModel(CSharpFormattingOptions2.SpaceBetweenParentheses, (int)SpacePlacementWithinParentheses.TypeCasts, CSharpVSResources.Insert_space_within_parentheses_of_type_casts, s_castPreview, this, optionStore, spaceBetweenParenthesesStorage, s_spaceBetweenParenthesesConversions)); + Items.Add(new CheckBoxEnumFlagsOptionViewModel(CSharpFormattingOptions2.SpaceBetweenParentheses, (int)SpacePlacementWithinParentheses.ControlFlowStatements, CSharpVSResources.Insert_spaces_within_parentheses_of_control_flow_statements, s_forDelimiterPreview, this, optionStore, spaceBetweenParenthesesStorage, s_spaceBetweenParenthesesConversions)); + Items.Add(new CheckBoxOptionViewModel(CSharpFormattingOptions2.SpaceAfterCast, CSharpVSResources.Insert_space_after_cast, s_castPreview, this, optionStore)); Items.Add(new CheckBoxOptionViewModel(CSharpFormattingOptions2.SpacesIgnoreAroundVariableDeclaration, CSharpVSResources.Ignore_spaces_in_declaration_statements, s_declarationSpacingPreview, this, optionStore)); diff --git a/src/VisualStudio/CSharp/Impl/Options/Formatting/StyleViewModel.cs b/src/VisualStudio/CSharp/Impl/Options/Formatting/StyleViewModel.cs index 0c1e270ded1d3..990c811d5c958 100644 --- a/src/VisualStudio/CSharp/Impl/Options/Formatting/StyleViewModel.cs +++ b/src/VisualStudio/CSharp/Impl/Options/Formatting/StyleViewModel.cs @@ -2309,25 +2309,25 @@ internal StyleViewModel(OptionStore optionStore, IServiceProvider serviceProvide private void AddParenthesesOptions(OptionStore optionStore) { AddParenthesesOption( - LanguageNames.CSharp, optionStore, CodeStyleOptions2.ArithmeticBinaryParentheses, + optionStore, CodeStyleOptions2.ArithmeticBinaryParentheses, CSharpVSResources.In_arithmetic_binary_operators, new[] { s_arithmeticBinaryAlwaysForClarity, s_arithmeticBinaryNeverIfUnnecessary }, defaultAddForClarity: true); AddParenthesesOption( - LanguageNames.CSharp, optionStore, CodeStyleOptions2.OtherBinaryParentheses, + optionStore, CodeStyleOptions2.OtherBinaryParentheses, CSharpVSResources.In_other_binary_operators, new[] { s_otherBinaryAlwaysForClarity, s_otherBinaryNeverIfUnnecessary }, defaultAddForClarity: true); AddParenthesesOption( - LanguageNames.CSharp, optionStore, CodeStyleOptions2.RelationalBinaryParentheses, + optionStore, CodeStyleOptions2.RelationalBinaryParentheses, CSharpVSResources.In_relational_binary_operators, new[] { s_relationalBinaryAlwaysForClarity, s_relationalBinaryNeverIfUnnecessary }, defaultAddForClarity: true); AddParenthesesOption( - LanguageNames.CSharp, optionStore, CodeStyleOptions2.OtherParentheses, + optionStore, CodeStyleOptions2.OtherParentheses, ServicesVSResources.In_other_operators, new[] { s_otherParenthesesAlwaysForClarity, s_otherParenthesesNeverIfUnnecessary }, defaultAddForClarity: false); @@ -2481,7 +2481,7 @@ private void AddParameterOptions(OptionStore optionStore, string parameterPrefer s_avoidUnusedParametersAllMethods }; - AddUnusedParameterOption(LanguageNames.CSharp, optionStore, parameterPreferencesGroupTitle, examples); + AddUnusedParameterOption(optionStore, parameterPreferencesGroupTitle, examples); } } } diff --git a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.ICSInputSet.cs b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.ICSInputSet.cs index 147a876e9f44a..0b7b203e7f767 100644 --- a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.ICSInputSet.cs +++ b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.ICSInputSet.cs @@ -45,12 +45,12 @@ public void SetOutputFileName(string filename) // Some projects like web projects give us just a filename; those aren't really useful (they're just filler) so we'll ignore them for purposes of tracking the path if (PathUtilities.IsAbsolute(filename)) { - VisualStudioProject.CompilationOutputAssemblyFilePath = filename; + ProjectSystemProject.CompilationOutputAssemblyFilePath = filename; } if (filename != null) { - VisualStudioProject.AssemblyName = Path.GetFileNameWithoutExtension(filename); + ProjectSystemProject.AssemblyName = Path.GetFileNameWithoutExtension(filename); } RefreshBinOutputPath(); diff --git a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.ICSharpProjectSite.cs b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.ICSharpProjectSite.cs index 10daf994f1fd6..b87a4b0820fb1 100644 --- a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.ICSharpProjectSite.cs +++ b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.ICSharpProjectSite.cs @@ -72,7 +72,7 @@ public int OnImportAddedEx(string filename, string project, CompilerOptions opti } var embedInteropTypes = optionID == CompilerOptions.OPTID_IMPORTSUSINGNOPIA; - VisualStudioProject.AddMetadataReference(filename, new MetadataReferenceProperties(embedInteropTypes: embedInteropTypes)); + ProjectSystemProject.AddMetadataReference(filename, new MetadataReferenceProperties(embedInteropTypes: embedInteropTypes)); return VSConstants.S_OK; } @@ -81,7 +81,7 @@ public void OnImportRemoved(string filename, string project) { filename = FileUtilities.NormalizeAbsolutePath(filename); - VisualStudioProject.RemoveMetadataReference(filename, VisualStudioProject.GetPropertiesForMetadataReference(filename).Single()); + ProjectSystemProject.RemoveMetadataReference(filename, properties: ProjectSystemProject.GetPropertiesForMetadataReference(filename).Single()); } public void OnOutputFileChanged(string filename) @@ -120,7 +120,7 @@ public void OnModuleRemoved(string filename) public int GetValidStartupClasses(IntPtr[] classNames, ref int count) { - var project = Workspace.CurrentSolution.GetRequiredProject(VisualStudioProject.Id); + var project = Workspace.CurrentSolution.GetRequiredProject(ProjectSystemProject.Id); var compilation = project.GetRequiredCompilationAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None); var entryPoints = EntryPointFinder.FindEntryPoints(compilation.SourceModule.GlobalNamespace); @@ -164,11 +164,11 @@ public int GetValidStartupClasses(IntPtr[] classNames, ref int count) public void OnAliasesChanged(string file, string project, int previousAliasesCount, string[] previousAliases, int currentAliasesCount, string[] currentAliases) { - using (VisualStudioProject.CreateBatchScope()) + using (ProjectSystemProject.CreateBatchScope()) { - var existingProperties = VisualStudioProject.GetPropertiesForMetadataReference(file).Single(); - VisualStudioProject.RemoveMetadataReference(file, existingProperties); - VisualStudioProject.AddMetadataReference(file, existingProperties.WithAliases(currentAliases)); + var existingProperties = ProjectSystemProject.GetPropertiesForMetadataReference(file).Single(); + ProjectSystemProject.RemoveMetadataReference(file, existingProperties); + ProjectSystemProject.AddMetadataReference(file, existingProperties.WithAliases(currentAliases)); } } } diff --git a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.ICSharpVenusProjectSite.cs b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.ICSharpVenusProjectSite.cs index 84e630af96813..60e60d2839476 100644 --- a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.ICSharpVenusProjectSite.cs +++ b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.ICSharpVenusProjectSite.cs @@ -21,7 +21,7 @@ public void RemoveReferenceToCodeDirectory(string assemblyFileName, ICSharpProje { var projectSite = GetProjectSite(project); - var projectReferencesToRemove = VisualStudioProject.GetProjectReferences().Where(p => p.ProjectId == projectSite.VisualStudioProject.Id).ToList(); + var projectReferencesToRemove = ProjectSystemProject.GetProjectReferences().Where(p => p.ProjectId == projectSite.ProjectSystemProject.Id).ToList(); if (projectReferencesToRemove.Count == 0) { @@ -30,7 +30,7 @@ public void RemoveReferenceToCodeDirectory(string assemblyFileName, ICSharpProje foreach (var projectReferenceToRemove in projectReferencesToRemove) { - VisualStudioProject.RemoveProjectReference(new ProjectReference(projectSite.VisualStudioProject.Id)); + ProjectSystemProject.RemoveProjectReference(new ProjectReference(projectSite.ProjectSystemProject.Id)); } } @@ -41,12 +41,12 @@ public void OnCodeDirectoryAliasesChanged(ICSharpProjectRoot project, int previo { var projectSite = GetProjectSite(project); - using (VisualStudioProject.CreateBatchScope()) + using (ProjectSystemProject.CreateBatchScope()) { - var existingProjectReference = VisualStudioProject.GetProjectReferences().Single(p => p.ProjectId == projectSite.VisualStudioProject.Id); + var existingProjectReference = ProjectSystemProject.GetProjectReferences().Single(p => p.ProjectId == projectSite.ProjectSystemProject.Id); - VisualStudioProject.RemoveProjectReference(existingProjectReference); - VisualStudioProject.AddProjectReference(new ProjectReference(existingProjectReference.ProjectId, ImmutableArray.Create(currentAliases), existingProjectReference.EmbedInteropTypes)); + ProjectSystemProject.RemoveProjectReference(existingProjectReference); + ProjectSystemProject.AddProjectReference(new ProjectReference(existingProjectReference.ProjectId, ImmutableArray.Create(currentAliases), existingProjectReference.EmbedInteropTypes)); } } @@ -54,7 +54,7 @@ public void AddReferenceToCodeDirectoryEx(string assemblyFileName, ICSharpProjec { var projectSite = GetProjectSite(projectRoot); - VisualStudioProject.AddProjectReference(new ProjectReference(projectSite.VisualStudioProject.Id, embedInteropTypes: optionID == CompilerOptions.OPTID_IMPORTSUSINGNOPIA)); + ProjectSystemProject.AddProjectReference(new ProjectReference(projectSite.ProjectSystemProject.Id, embedInteropTypes: optionID == CompilerOptions.OPTID_IMPORTSUSINGNOPIA)); } /// diff --git a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.OptionsProcessor.cs b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.OptionsProcessor.cs index 133dfaf01e672..84704e93e1593 100644 --- a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.OptionsProcessor.cs +++ b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.OptionsProcessor.cs @@ -9,6 +9,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Workspaces.ProjectSystem; using Microsoft.VisualStudio.LanguageServices.CSharp.ProjectSystemShim.Interop; using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; using Roslyn.Utilities; @@ -19,16 +20,16 @@ internal partial class CSharpProjectShim { private class OptionsProcessor : VisualStudioProjectOptionsProcessor { - private readonly VisualStudioProject _visualStudioProject; + private readonly ProjectSystemProject _projectSystemProject; private readonly object[] _options = new object[(int)CompilerOptions.LARGEST_OPTION_ID]; private string? _mainTypeName; private OutputKind _outputKind; - public OptionsProcessor(VisualStudioProject visualStudioProject, SolutionServices workspaceServices) - : base(visualStudioProject, workspaceServices) + public OptionsProcessor(ProjectSystemProject projectSystemProject, SolutionServices workspaceServices) + : base(projectSystemProject, workspaceServices) { - _visualStudioProject = visualStudioProject; + _projectSystemProject = projectSystemProject; } public object this[CompilerOptions compilerOption] @@ -187,7 +188,7 @@ private bool GetBooleanOption(CompilerOptions optionID) return null; } - var directory = Path.GetDirectoryName(_visualStudioProject.FilePath); + var directory = Path.GetDirectoryName(_projectSystemProject.FilePath); if (!string.IsNullOrEmpty(directory)) { diff --git a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.cs b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.cs index f8c001cb6a312..f83b0c88d49cc 100644 --- a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.cs +++ b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.cs @@ -66,8 +66,8 @@ public CSharpProjectShim( var componentModel = (IComponentModel)serviceProvider.GetService(typeof(SComponentModel)); - this.ProjectCodeModel = componentModel.GetService().CreateProjectCodeModel(VisualStudioProject.Id, this); - this.VisualStudioProjectOptionsProcessor = new OptionsProcessor(this.VisualStudioProject, Workspace.Services.SolutionServices); + this.ProjectCodeModel = componentModel.GetService().CreateProjectCodeModel(ProjectSystemProject.Id, this); + this.VisualStudioProjectOptionsProcessor = new OptionsProcessor(this.ProjectSystemProject, Workspace.Services.SolutionServices); // Ensure the default options are set up ResetAllOptions(); diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.cs.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.cs.xlf index 5fcfe7d50942a..f6647062f8b87 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.cs.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.cs.xlf @@ -9,17 +9,17 @@ Allow blank line after colon in constructor initializer - Allow blank line after colon in constructor initializer + Povolit prázdný řádek za dvojtečkou v inicializátoru konstruktoru Allow blank line after token in arrow expression clause - Allow blank line after token in arrow expression clause + Povolit prázdný řádek za tokenem v klauzuli výrazu šipky. Allow blank line after token in conditional expression - Allow blank line after token in conditional expression + Povolit prázdný řádek za tokenem v podmíněném výrazu. @@ -114,12 +114,12 @@ Insert space between called method name and its opening parenthesis - Insert space between called method name and its opening parenthesis + Vložit mezeru mezi název volané metody a její levou závorku. Insert space between method name and its opening parenthesis - Insert space between method name and its opening parenthesis + Vložit mezeru mezi název metody a její levou kulatou závorkou diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.de.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.de.xlf index 403669d447bb3..5ad146f6ac679 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.de.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.de.xlf @@ -9,17 +9,17 @@ Allow blank line after colon in constructor initializer - Allow blank line after colon in constructor initializer + Leere Zeile nach Doppelpunkt in Konstruktorinitialisierer zulassen Allow blank line after token in arrow expression clause - Allow blank line after token in arrow expression clause + Leere Zeile nach Token in Pfeilausdrucksklausel zulassen Allow blank line after token in conditional expression - Allow blank line after token in conditional expression + Leere Zeile nach Token im bedingten Ausdruck zulassen @@ -114,12 +114,12 @@ Insert space between called method name and its opening parenthesis - Insert space between called method name and its opening parenthesis + Leerzeichen zwischen aufgerufenem Methodennamen und ihrer runden Klammer links einfügen Insert space between method name and its opening parenthesis - Insert space between method name and its opening parenthesis + Leerzeichen zwischen Methodenname und öffnender runder Klammer einfügen diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.es.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.es.xlf index 06307672636f8..b2f05f1e85210 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.es.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.es.xlf @@ -9,17 +9,17 @@ Allow blank line after colon in constructor initializer - Allow blank line after colon in constructor initializer + Permitir una línea en blanco después de dos puntos en el inicializador del constructor Allow blank line after token in arrow expression clause - Allow blank line after token in arrow expression clause + Permitir línea en blanco después del token en la cláusula de expresión de flecha Allow blank line after token in conditional expression - Allow blank line after token in conditional expression + Permitir línea en blanco después del token en la expresión condicional @@ -114,12 +114,12 @@ Insert space between called method name and its opening parenthesis - Insert space between called method name and its opening parenthesis + Insertar espacio entre el nombre del método llamado y el paréntesis de apertura Insert space between method name and its opening parenthesis - Insert space between method name and its opening parenthesis + Insertar espacio entre el nombre del método y el paréntesis de apertura diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.fr.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.fr.xlf index 04a65985f2dcd..cf6a1aece0a23 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.fr.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.fr.xlf @@ -9,17 +9,17 @@ Allow blank line after colon in constructor initializer - Allow blank line after colon in constructor initializer + Autoriser une ligne vide après le signe des deux-points dans l'initialiseur du constructeur Allow blank line after token in arrow expression clause - Allow blank line after token in arrow expression clause + Autoriser une ligne vide après le jeton dans la clause d’expression fléchée Allow blank line after token in conditional expression - Allow blank line after token in conditional expression + Autoriser une ligne vide après le jeton dans une expression conditionnelle @@ -114,12 +114,12 @@ Insert space between called method name and its opening parenthesis - Insert space between called method name and its opening parenthesis + Insérer un espace entre le nom de la méthode appelée et sa parenthèse ouvrante Insert space between method name and its opening parenthesis - Insert space between method name and its opening parenthesis + Insérer un espace entre le nom de la méthode et sa parenthèse ouvrante diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.it.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.it.xlf index 2a34d3596375e..9b2605c684ad2 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.it.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.it.xlf @@ -9,17 +9,17 @@ Allow blank line after colon in constructor initializer - Allow blank line after colon in constructor initializer + Consenti riga vuota dopo i due punti nell'inizializzatore del costruttore Allow blank line after token in arrow expression clause - Allow blank line after token in arrow expression clause + Consentire una riga vuota dopo il token nella clausola di espressione arrow Allow blank line after token in conditional expression - Allow blank line after token in conditional expression + Consentire una riga vuota dopo il token nell'espressione condizionale @@ -114,12 +114,12 @@ Insert space between called method name and its opening parenthesis - Insert space between called method name and its opening parenthesis + Inserire uno spazio tra il nome del metodo chiamato e la parentesi aperta Insert space between method name and its opening parenthesis - Insert space between method name and its opening parenthesis + Inserisci spazio tra il nome del metodo e la parentesi di apertura corrispondente diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ja.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ja.xlf index 2c9cf8c401770..555157cf1cc7f 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ja.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ja.xlf @@ -9,17 +9,17 @@ Allow blank line after colon in constructor initializer - Allow blank line after colon in constructor initializer + コンストラクター初期化子のコロンの後に空白行を許可する Allow blank line after token in arrow expression clause - Allow blank line after token in arrow expression clause + 矢印式句でトークンの後に空白行を許可します Allow blank line after token in conditional expression - Allow blank line after token in conditional expression + 条件式でトークンの後に空白行を許可します @@ -114,12 +114,12 @@ Insert space between called method name and its opening parenthesis - Insert space between called method name and its opening parenthesis + 呼び出されたメソッド名と始めかっこの間にスペースを挿入します Insert space between method name and its opening parenthesis - Insert space between method name and its opening parenthesis + メソッド名と始めかっこの間にスペースを挿入する diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ko.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ko.xlf index 8b6f405707a81..df61b1e5f5b37 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ko.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ko.xlf @@ -9,17 +9,17 @@ Allow blank line after colon in constructor initializer - Allow blank line after colon in constructor initializer + 생성자 이니셜라이저의 콜론 뒤에 빈 줄 허용 Allow blank line after token in arrow expression clause - Allow blank line after token in arrow expression clause + 화살표 식 절에서 토큰 뒤에 빈 줄 허용 Allow blank line after token in conditional expression - Allow blank line after token in conditional expression + 조건식에서 토큰 뒤에 빈 줄 허용 @@ -114,12 +114,12 @@ Insert space between called method name and its opening parenthesis - Insert space between called method name and its opening parenthesis + 호출한 메서드 이름과 여는 괄호 사이에 공백 삽입 Insert space between method name and its opening parenthesis - Insert space between method name and its opening parenthesis + 메서드 이름과 여는 괄호 사이에 공백 삽입 diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pl.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pl.xlf index 97b8b25cda397..c81758714e2af 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pl.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pl.xlf @@ -9,17 +9,17 @@ Allow blank line after colon in constructor initializer - Allow blank line after colon in constructor initializer + Zezwalaj na pusty wiersz po dwukropku w inicjatorze konstruktora Allow blank line after token in arrow expression clause - Allow blank line after token in arrow expression clause + Zezwalaj na pusty wiersz po tokenie w klauzuli wyrażenia strzałki Allow blank line after token in conditional expression - Allow blank line after token in conditional expression + Zezwalaj na pusty wiersz po tokenie w wyrażeniu warunkowym @@ -114,12 +114,12 @@ Insert space between called method name and its opening parenthesis - Insert space between called method name and its opening parenthesis + Wstaw spację między nazwą wywołanej metody a jej nawias otwierający Insert space between method name and its opening parenthesis - Insert space between method name and its opening parenthesis + Wstaw spację między nazwę metody i jej nawias otwierający diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pt-BR.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pt-BR.xlf index f3b47a01e0a1b..f2c4333a4de16 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pt-BR.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pt-BR.xlf @@ -9,17 +9,17 @@ Allow blank line after colon in constructor initializer - Allow blank line after colon in constructor initializer + Permitir uma linha em branco após os dois-pontos no inicializador do construtor Allow blank line after token in arrow expression clause - Allow blank line after token in arrow expression clause + Permitir linha em branco após o token na cláusula de expressão de seta Allow blank line after token in conditional expression - Allow blank line after token in conditional expression + Permitir linha em branco após o token na expressão condicional @@ -114,12 +114,12 @@ Insert space between called method name and its opening parenthesis - Insert space between called method name and its opening parenthesis + Inserir espaço entre o nome do método chamado e seu parêntese de abertura Insert space between method name and its opening parenthesis - Insert space between method name and its opening parenthesis + Inserir espaço entre o nome do método e o parêntese inicial diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ru.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ru.xlf index c4d3a2cccf393..3394c8cde9d4c 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ru.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ru.xlf @@ -9,17 +9,17 @@ Allow blank line after colon in constructor initializer - Allow blank line after colon in constructor initializer + Разрешать пустую строку после двоеточия в инициализаторе конструктора Allow blank line after token in arrow expression clause - Allow blank line after token in arrow expression clause + Разрешить пустую строку после маркера в предложении выражения со стрелкой Allow blank line after token in conditional expression - Allow blank line after token in conditional expression + Разрешить пустую строку после маркера в условном выражении @@ -114,12 +114,12 @@ Insert space between called method name and its opening parenthesis - Insert space between called method name and its opening parenthesis + Вставлять пробел между именем вызванного метода и открывающей скобкой Insert space between method name and its opening parenthesis - Insert space between method name and its opening parenthesis + Вставлять пробел между именем метода и открывающей скобкой diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.tr.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.tr.xlf index 1e8cccb9c6ec0..0399f90e03d69 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.tr.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.tr.xlf @@ -9,17 +9,17 @@ Allow blank line after colon in constructor initializer - Allow blank line after colon in constructor initializer + Oluşturucu başlatıcıda iki noktadan sonra boş satıra izin ver Allow blank line after token in arrow expression clause - Allow blank line after token in arrow expression clause + Ok ifadesi yan tümcesinde belirteçten sonra boş satıra izin ver Allow blank line after token in conditional expression - Allow blank line after token in conditional expression + Koşullu ifadede belirteçten sonra boş satıra izin ver @@ -114,12 +114,12 @@ Insert space between called method name and its opening parenthesis - Insert space between called method name and its opening parenthesis + Metodun adı ile açma ayracı arasına boşluk ekle Insert space between method name and its opening parenthesis - Insert space between method name and its opening parenthesis + Metot adı ile metodun açma ayracı arasına boşluk ekle @@ -579,7 +579,7 @@ _Insert * at the start of new lines when writing /* */ comments - _/* */ açıklamaları yazarken her yeni satırın başına * ekle + _/* */ açıklamaları yazarken her yeni satırın başına _ekle * diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hans.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hans.xlf index 376d478549462..5abcd13ff0c9a 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hans.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hans.xlf @@ -9,17 +9,17 @@ Allow blank line after colon in constructor initializer - Allow blank line after colon in constructor initializer + 允许在构造函数初始值设定项中的冒号后面使用空白行 Allow blank line after token in arrow expression clause - Allow blank line after token in arrow expression clause + 在箭头表达式子句中允许标记后的空行 Allow blank line after token in conditional expression - Allow blank line after token in conditional expression + 在条件表达式中允许标记后的空行 @@ -114,12 +114,12 @@ Insert space between called method name and its opening parenthesis - Insert space between called method name and its opening parenthesis + 在调用的方法名称与其左括号之间插入空格 Insert space between method name and its opening parenthesis - Insert space between method name and its opening parenthesis + 在方法名称与其左括号之间插入空格 diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hant.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hant.xlf index ed07b95bd7b18..4a201036bd701 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hant.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hant.xlf @@ -9,17 +9,17 @@ Allow blank line after colon in constructor initializer - Allow blank line after colon in constructor initializer + 允許在建構函式初始設定式的冒號後面加上空白行 Allow blank line after token in arrow expression clause - Allow blank line after token in arrow expression clause + 在箭頭運算式子句中的權杖後允許空白行 Allow blank line after token in conditional expression - Allow blank line after token in conditional expression + 在條件運算式中的權杖後允許空白行 @@ -114,12 +114,12 @@ Insert space between called method name and its opening parenthesis - Insert space between called method name and its opening parenthesis + 在方法名稱和左括弧之間插入空格 Insert space between method name and its opening parenthesis - Insert space between method name and its opening parenthesis + 在方法名稱和左括號之間插入空格 diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.zh-Hans.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.zh-Hans.xlf index 13f80cfb1c600..f56c59486fa8f 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.zh-Hans.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.zh-Hans.xlf @@ -115,7 +115,7 @@ Using 指令; 大纲; 在文件打开时进入大纲模式; 文件打开时折叠#regions; -文件打开时折叠using: +文件打开时折叠using; 文件打开时折叠元数据实现; 显示过程行分隔符; 显示声明级别构造的大纲; diff --git a/src/VisualStudio/CSharp/Test/EditorConfigSettings/DataProvider/DataProviderTests.cs b/src/VisualStudio/CSharp/Test/EditorConfigSettings/DataProvider/DataProviderTests.cs index 07123ed41a325..cc30ed940278c 100644 --- a/src/VisualStudio/CSharp/Test/EditorConfigSettings/DataProvider/DataProviderTests.cs +++ b/src/VisualStudio/CSharp/Test/EditorConfigSettings/DataProvider/DataProviderTests.cs @@ -115,14 +115,16 @@ public void TestGettingCodeStyleSettingProviderWorkspaceServiceAsync() var dataSnapShot = settingsProvider.GetCurrentDataSnapshot(); // We need to substract for string options that are not yet supported. - // CodeStyleOptions2.OperatorPlacementWhenWrapping - // CodeStyleOptions2.FileHeaderTemplate - // CodeStyleOptions2.RemoveUnnecessarySuppressionExclusions - // - // We also subtract for this not-yet supported option, tracked by https://github.com/dotnet/roslyn/issues/62937 - // CodeStyleOptions2.ForEachExplicitCastInSource - var optionsCount = CodeStyleOptions2.AllOptions.Where(x => x.StorageLocations.Any(y => y is IEditorConfigStorageLocation2)).Count() - 4; - Assert.Equal(optionsCount, dataSnapShot.Length); + // https://github.com/dotnet/roslyn/issues/62937 + var optionsWithUI = CodeStyleOptions2.AllOptions + .Remove(CodeStyleOptions2.OperatorPlacementWhenWrapping) + .Remove(CodeStyleOptions2.FileHeaderTemplate) + .Remove(CodeStyleOptions2.RemoveUnnecessarySuppressionExclusions) + .Remove(CodeStyleOptions2.ForEachExplicitCastInSource); + + AssertEx.Equal( + optionsWithUI.OrderBy(o => o.Definition.ConfigName), + dataSnapShot.Select(setting => setting.Key.Option).OrderBy(o => o.Definition.ConfigName)); } [Fact] @@ -162,9 +164,12 @@ public void TestGettingCodeStyleSettingsProviderLanguageServiceAsync() var model = new TestViewModel(); settingsProvider.RegisterViewModel(model); var dataSnapShot = settingsProvider.GetCurrentDataSnapshot(); - // We don't support PreferredModifierOrder yet so we subtract by one - var optionsCount = CSharpCodeStyleOptions.AllOptions.Where(x => x.StorageLocations.Any(y => y is IEditorConfigStorageLocation2)).Count() - 1; - Assert.Equal(optionsCount, dataSnapShot.Length); + + // We don't support PreferredModifierOrder yet: + var optionsWithUI = CSharpCodeStyleOptions.AllOptions + .Remove(CSharpCodeStyleOptions.PreferredModifierOrder); + + AssertEx.SetEqual(optionsWithUI, dataSnapShot.Select(setting => setting.Key.Option)); } [Fact] @@ -176,7 +181,7 @@ public void TestGettingWhitespaceSettingProviderWorkspaceServiceAsync() settingsProvider.RegisterViewModel(model); var dataSnapShot = settingsProvider.GetCurrentDataSnapshot(); - var expectedOptions = new IOption[] + var expectedOptions = new IOption2[] { FormattingOptions2.IndentationSize, FormattingOptions2.InsertFinalNewLine, @@ -186,9 +191,9 @@ public void TestGettingWhitespaceSettingProviderWorkspaceServiceAsync() CodeStyleOptions2.OperatorPlacementWhenWrapping }; - AssertEx.SetEqual( - expectedOptions.Select(option => option.Name), - dataSnapShot.Select(item => item.Key.Option.Name)); + AssertEx.Equal( + expectedOptions.Select(option => option.Definition.ConfigName).OrderBy(n => n), + dataSnapShot.Select(item => item.Key.Option.Definition.ConfigName).OrderBy(n => n)); } [Fact] @@ -201,10 +206,8 @@ public void TestGettingWhitespaceSettingProviderLanguageServiceAsync() var dataSnapshot = settingsProvider.GetCurrentDataSnapshot(); // multiple settings may share the same option (e.g. settings representing flags of an enum): - var optionsForSettings = dataSnapshot.GroupBy(s => s.Option).Select(g => g.Key).ToArray(); - - var optionsCount = CSharpFormattingOptions2.AllOptions.Where(x => x.StorageLocations.Any(y => y is IEditorConfigStorageLocation2)).Count(); - Assert.Equal(optionsCount, optionsForSettings.Length); + var optionsForSettings = dataSnapshot.GroupBy(s => s.Key.Option).Select(g => g.Key).ToArray(); + AssertEx.SetEqual(CSharpFormattingOptions2.AllOptions, optionsForSettings); } [Fact] diff --git a/src/VisualStudio/CSharp/Test/Options/OptionViewModelTests.cs b/src/VisualStudio/CSharp/Test/Options/OptionViewModelTests.cs index 4e98b5623bcd9..9a52008c9a3d0 100644 --- a/src/VisualStudio/CSharp/Test/Options/OptionViewModelTests.cs +++ b/src/VisualStudio/CSharp/Test/Options/OptionViewModelTests.cs @@ -53,7 +53,7 @@ public void TestCheckBox() { using var workspace = TestWorkspace.CreateCSharp(""); var serviceProvider = new MockServiceProvider(workspace.ExportProvider); - var optionStore = new OptionStore(workspace.Options); + var optionStore = new OptionStore(workspace.GlobalOptions); using var viewModel = new SpacingViewModel(optionStore, serviceProvider); // Use the first item's preview. var checkbox = viewModel.Items.OfType().First(); @@ -75,8 +75,8 @@ public void TestCheckBox() public void TestOptionLoading() { using var workspace = TestWorkspace.CreateCSharp(""); - var optionSet = workspace.Options.WithChangedOption(CSharpFormattingOptions2.SpacingAfterMethodDeclarationName, true); - var optionStore = new OptionStore(optionSet); + var optionStore = new OptionStore(workspace.GlobalOptions); + workspace.GlobalOptions.SetGlobalOption(CSharpFormattingOptions2.SpacingAfterMethodDeclarationName, true); var serviceProvider = new MockServiceProvider(workspace.ExportProvider); using var viewModel = new SpacingViewModel(optionStore, serviceProvider); @@ -90,7 +90,7 @@ public void TestOptionSaving() { using var workspace = TestWorkspace.CreateCSharp(""); var serviceProvider = new MockServiceProvider(workspace.ExportProvider); - var optionStore = new OptionStore(workspace.Options); + var optionStore = new OptionStore(workspace.GlobalOptions); using var viewModel = new SpacingViewModel(optionStore, serviceProvider); // Use the first item's preview. var checkbox = viewModel.Items.OfType().Where(c => c.Option == CSharpFormattingOptions2.SpacingAfterMethodDeclarationName).First(); diff --git a/src/VisualStudio/CSharp/Test/ProjectSystemShim/LegacyProject/CSharpCompilerOptionsTests.cs b/src/VisualStudio/CSharp/Test/ProjectSystemShim/LegacyProject/CSharpCompilerOptionsTests.cs index e8edaf4174ef4..9de1291b29a75 100644 --- a/src/VisualStudio/CSharp/Test/ProjectSystemShim/LegacyProject/CSharpCompilerOptionsTests.cs +++ b/src/VisualStudio/CSharp/Test/ProjectSystemShim/LegacyProject/CSharpCompilerOptionsTests.cs @@ -111,7 +111,7 @@ public void ProjectOutputPathAndOutputExeNameChange() Assert.Equal(initialPath, project.GetOutputFileName()); string getCurrentCompilationOutputAssemblyPath() - => environment.Workspace.CurrentSolution.GetRequiredProject(project.Test_VisualStudioProject.Id).CompilationOutputInfo.AssemblyPath; + => environment.Workspace.CurrentSolution.GetRequiredProject(project.Test_ProjectSystemProject.Id).CompilationOutputInfo.AssemblyPath; Assert.Equal(initialPath, getCurrentCompilationOutputAssemblyPath()); @@ -144,7 +144,7 @@ public void ProjectCompilationOutputsChange() var project = CSharpHelpers.CreateCSharpProject(environment, "Test"); string getCurrentCompilationOutputAssemblyPath() - => environment.Workspace.CurrentSolution.GetRequiredProject(project.Test_VisualStudioProject.Id).CompilationOutputInfo.AssemblyPath; + => environment.Workspace.CurrentSolution.GetRequiredProject(project.Test_ProjectSystemProject.Id).CompilationOutputInfo.AssemblyPath; Assert.Null(getCurrentCompilationOutputAssemblyPath()); diff --git a/src/VisualStudio/Core/Def/ChangeSignature/AddParameterDialog.xaml b/src/VisualStudio/Core/Def/ChangeSignature/AddParameterDialog.xaml index a7936ebe79a2e..5b4f055d8b938 100644 --- a/src/VisualStudio/Core/Def/ChangeSignature/AddParameterDialog.xaml +++ b/src/VisualStudio/Core/Def/ChangeSignature/AddParameterDialog.xaml @@ -141,7 +141,7 @@ + Orientation="Horizontal"> + Orientation="Horizontal"> otherProjectsForMultiTfmProject; + if (project != null) + { + otherProjectsForMultiTfmProject = solution.Projects.Where( + p => p != project && p.FilePath == project.FilePath && p.State.NameAndFlavor.name == project.State.NameAndFlavor.name).ToImmutableArray(); + if (!otherProjectsForMultiTfmProject.IsEmpty) + projectOrSolutionName = project.State.NameAndFlavor.name; + } + else + { + otherProjectsForMultiTfmProject = ImmutableArray.Empty; + } + bool isAnalysisDisabled; if (project != null) { @@ -323,9 +337,9 @@ public void RunAnalyzers(IVsHierarchy? hierarchy) // Add a message to VS status bar that we are running code analysis. var statusBar = _serviceProvider?.GetService(typeof(SVsStatusbar)) as IVsStatusbar; - var totalProjectCount = project != null ? 1 : (uint)solution.ProjectIds.Count; + var totalProjectCount = project != null ? (1 + otherProjectsForMultiTfmProject.Length) : solution.ProjectIds.Count; var statusBarUpdater = statusBar != null - ? new StatusBarUpdater(statusBar, _threadingContext, projectOrSolutionName, totalProjectCount) + ? new StatusBarUpdater(statusBar, _threadingContext, projectOrSolutionName, (uint)totalProjectCount) : null; // Force complete analyzer execution in background. @@ -337,6 +351,9 @@ public void RunAnalyzers(IVsHierarchy? hierarchy) var onProjectAnalyzed = statusBarUpdater != null ? statusBarUpdater.OnProjectAnalyzed : (Action)((Project _) => { }); await _diagnosticService.ForceAnalyzeAsync(solution, onProjectAnalyzed, project?.Id, CancellationToken.None).ConfigureAwait(false); + foreach (var otherProject in otherProjectsForMultiTfmProject) + await _diagnosticService.ForceAnalyzeAsync(solution, onProjectAnalyzed, otherProject.Id, CancellationToken.None).ConfigureAwait(false); + // If user has disabled live analyzer execution for any project(s), i.e. set RunAnalyzersDuringLiveAnalysis = false, // then ForceAnalyzeAsync will not cause analyzers to execute. // We explicitly fetch diagnostics for such projects and report these as "Host" diagnostics. @@ -355,7 +372,7 @@ void HandleProjectsWithDisabledAnalysis() RoslynDebug.Assert(solution != null); // First clear all special host diagostics for all involved projects. - var projects = project != null ? SpecializedCollections.SingletonEnumerable(project) : solution.Projects; + var projects = project != null ? otherProjectsForMultiTfmProject.Add(project) : solution.Projects; foreach (var project in projects) { _hostDiagnosticUpdateSource.ClearDiagnosticsForProject(project.Id, key: this); diff --git a/src/VisualStudio/Core/Def/DocumentOutline/DocumentOutlineOptionsMetadata.cs b/src/VisualStudio/Core/Def/DocumentOutline/DocumentOutlineOptionsMetadata.cs index 8e0a6e1ad45bb..d859f2c314dfe 100644 --- a/src/VisualStudio/Core/Def/DocumentOutline/DocumentOutlineOptionsMetadata.cs +++ b/src/VisualStudio/Core/Def/DocumentOutline/DocumentOutlineOptionsMetadata.cs @@ -8,9 +8,6 @@ namespace Microsoft.VisualStudio.LanguageServices.DocumentOutline { internal sealed class DocumentOutlineOptionsMetadata { - private const string FeatureName = "DocumentOutlineOptions"; - - public static readonly Option2 EnableDocumentOutline = new(FeatureName, nameof(EnableDocumentOutline), defaultValue: false, - storageLocation: new FeatureFlagStorageLocation("Roslyn.DocumentOutline")); + public static readonly Option2 EnableDocumentOutline = new("DocumentOutlineOptions_EnableDocumentOutline", defaultValue: false); } } diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Common/SettingsViewModelBase.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Common/SettingsViewModelBase.cs index 92d3e67bcb117..cfac60ad710de 100644 --- a/src/VisualStudio/Core/Def/EditorConfigSettings/Common/SettingsViewModelBase.cs +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Common/SettingsViewModelBase.cs @@ -80,6 +80,8 @@ public IWpfTableControl4 GetTableControl() fixedColumns); control.KeepSelectionInView = true; + control.DoNotLoseFocusOnBucketExpandOrCollapse(); + return control; } diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Common/TableControlFocusFixer.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Common/TableControlFocusFixer.cs new file mode 100644 index 0000000000000..a0ade2173456e --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Common/TableControlFocusFixer.cs @@ -0,0 +1,40 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Controls; +using System.Windows.Input; +using Microsoft.VisualStudio.Shell.TableControl; + +namespace Microsoft.VisualStudio.LanguageServices +{ + internal static class TableControlFocusFixer + { + /// + /// A Workaround for a focus issue in the tabular data control. + /// When buckets are collapsed, depending on which element has focus at the time, + /// focus is shifted to the outer control making keyboard navigation difficult. + /// In some cases this behavior is fine (like the find-all-references tool window) + /// because we already navigate the user (and therefore change focus) to the symbol definition + /// on focus. Use this workaround in cases where we must not change keyboard focus. + /// + public static void DoNotLoseFocusOnBucketExpandOrCollapse(this IWpfTableControl tableControl) + { + tableControl.Control.PreviewLostKeyboardFocus += (object sender, KeyboardFocusChangedEventArgs e) => + { + // The tabular data control is a list view, the new focus changing to a different control tells us we've hit this case. + // This workaround will break if the underlying implementation of the tabular data control is changed someday. + if (e.NewFocus is not ListView && (e.KeyboardDevice.IsKeyDown(Key.Left) || e.KeyboardDevice.IsKeyDown(Key.Right))) + { + // Set handled to true to indicate that we want to not do this focus change. + e.Handled = true; + } + }; + } + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/DataProvider/CodeStyle/CommonCodeStyleSettingsProvider.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/DataProvider/CodeStyle/CommonCodeStyleSettingsProvider.cs index 789b66394a7c9..1a11218f1ff1a 100644 --- a/src/VisualStudio/Core/Def/EditorConfigSettings/DataProvider/CodeStyle/CommonCodeStyleSettingsProvider.cs +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/DataProvider/CodeStyle/CommonCodeStyleSettingsProvider.cs @@ -16,8 +16,8 @@ namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider.CodeSt { internal sealed class CommonCodeStyleSettingsProvider : SettingsProviderBase { - public CommonCodeStyleSettingsProvider(string filePath, OptionUpdater settingsUpdater, Workspace workspace) - : base(filePath, settingsUpdater, workspace) + public CommonCodeStyleSettingsProvider(string filePath, OptionUpdater settingsUpdater, Workspace workspace, IGlobalOptionService globalOptions) + : base(filePath, settingsUpdater, workspace, globalOptions) { Update(); } diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/DataProvider/CodeStyle/CommonCodeStyleSettingsProviderFactory.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/DataProvider/CodeStyle/CommonCodeStyleSettingsProviderFactory.cs index 2477ecf668c1c..7e39dd6ed8b82 100644 --- a/src/VisualStudio/Core/Def/EditorConfigSettings/DataProvider/CodeStyle/CommonCodeStyleSettingsProviderFactory.cs +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/DataProvider/CodeStyle/CommonCodeStyleSettingsProviderFactory.cs @@ -4,16 +4,22 @@ using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider.CodeStyle { - internal class CommonCodeStyleSettingsProviderFactory : IWorkspaceSettingsProviderFactory + internal sealed class CommonCodeStyleSettingsProviderFactory : IWorkspaceSettingsProviderFactory { private readonly Workspace _workspace; + private readonly IGlobalOptionService _globalOptions; - public CommonCodeStyleSettingsProviderFactory(Workspace workspace) => _workspace = workspace; + public CommonCodeStyleSettingsProviderFactory(Workspace workspace, IGlobalOptionService globalOptions) + { + _workspace = workspace; + _globalOptions = globalOptions; + } public ISettingsProvider GetForFile(string filePath) - => new CommonCodeStyleSettingsProvider(filePath, new OptionUpdater(_workspace, filePath), _workspace); + => new CommonCodeStyleSettingsProvider(filePath, new OptionUpdater(_workspace, filePath), _workspace, _globalOptions); } } diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/DataProvider/CodeStyle/CommonCodeStyleSettingsWorkspaceServiceFactory.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/DataProvider/CodeStyle/CommonCodeStyleSettingsWorkspaceServiceFactory.cs index 2a34627f74a2d..05497c2227910 100644 --- a/src/VisualStudio/Core/Def/EditorConfigSettings/DataProvider/CodeStyle/CommonCodeStyleSettingsWorkspaceServiceFactory.cs +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/DataProvider/CodeStyle/CommonCodeStyleSettingsWorkspaceServiceFactory.cs @@ -7,17 +7,23 @@ using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider.CodeStyle { [ExportWorkspaceServiceFactory(typeof(IWorkspaceSettingsProviderFactory)), Shared] - internal class CommonCodeStyleSettingsWorkspaceServiceFactory : IWorkspaceServiceFactory + internal sealed class CommonCodeStyleSettingsWorkspaceServiceFactory : IWorkspaceServiceFactory { + private readonly IGlobalOptionService _globalOptions; + [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CommonCodeStyleSettingsWorkspaceServiceFactory() { } + public CommonCodeStyleSettingsWorkspaceServiceFactory(IGlobalOptionService globalOptions) + { + _globalOptions = globalOptions; + } public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) - => new CommonCodeStyleSettingsProviderFactory(workspaceServices.Workspace); + => new CommonCodeStyleSettingsProviderFactory(workspaceServices.Workspace, _globalOptions); } } diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/DataProvider/Whitespace/CommonWhitespaceSettingsProvider.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/DataProvider/Whitespace/CommonWhitespaceSettingsProvider.cs index 30a4989dac936..efce63da12def 100644 --- a/src/VisualStudio/Core/Def/EditorConfigSettings/DataProvider/Whitespace/CommonWhitespaceSettingsProvider.cs +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/DataProvider/Whitespace/CommonWhitespaceSettingsProvider.cs @@ -15,8 +15,8 @@ namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider.Whites { internal sealed class CommonWhitespaceSettingsProvider : SettingsProviderBase { - public CommonWhitespaceSettingsProvider(string fileName, OptionUpdater settingsUpdater, Workspace workspace) - : base(fileName, settingsUpdater, workspace) + public CommonWhitespaceSettingsProvider(string fileName, OptionUpdater settingsUpdater, Workspace workspace, IGlobalOptionService globalOptions) + : base(fileName, settingsUpdater, workspace, globalOptions) { Update(); } diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/DataProvider/Whitespace/CommonWhitespaceSettingsProviderFactory.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/DataProvider/Whitespace/CommonWhitespaceSettingsProviderFactory.cs index 3c0a775d943a5..127189d90c9be 100644 --- a/src/VisualStudio/Core/Def/EditorConfigSettings/DataProvider/Whitespace/CommonWhitespaceSettingsProviderFactory.cs +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/DataProvider/Whitespace/CommonWhitespaceSettingsProviderFactory.cs @@ -4,17 +4,23 @@ using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider.Whitespace { - internal class CommonWhitespaceSettingsProviderFactory : IWorkspaceSettingsProviderFactory + internal sealed class CommonWhitespaceSettingsProviderFactory : IWorkspaceSettingsProviderFactory { private readonly Workspace _workspace; + private readonly IGlobalOptionService _globalOptions; - public CommonWhitespaceSettingsProviderFactory(Workspace workspace) => _workspace = workspace; + public CommonWhitespaceSettingsProviderFactory(Workspace workspace, IGlobalOptionService globalOptions) + { + _workspace = workspace; + _globalOptions = globalOptions; + } public ISettingsProvider GetForFile(string filePath) - => new CommonWhitespaceSettingsProvider(filePath, new OptionUpdater(_workspace, filePath), _workspace); + => new CommonWhitespaceSettingsProvider(filePath, new OptionUpdater(_workspace, filePath), _workspace, _globalOptions); } } diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/DataProvider/Whitespace/CommonWhitespaceSettingsWorkspaceServiceFactory.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/DataProvider/Whitespace/CommonWhitespaceSettingsWorkspaceServiceFactory.cs index 43759a9e44751..edaadc472bb53 100644 --- a/src/VisualStudio/Core/Def/EditorConfigSettings/DataProvider/Whitespace/CommonWhitespaceSettingsWorkspaceServiceFactory.cs +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/DataProvider/Whitespace/CommonWhitespaceSettingsWorkspaceServiceFactory.cs @@ -7,17 +7,23 @@ using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider.Whitespace { [ExportWorkspaceServiceFactory(typeof(IWorkspaceSettingsProviderFactory)), Shared] - internal class CommonWhitespaceSettingsWorkspaceServiceFactory : IWorkspaceServiceFactory + internal sealed class CommonWhitespaceSettingsWorkspaceServiceFactory : IWorkspaceServiceFactory { + private readonly IGlobalOptionService _globalOptions; + [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CommonWhitespaceSettingsWorkspaceServiceFactory() { } + public CommonWhitespaceSettingsWorkspaceServiceFactory(IGlobalOptionService globalOptions) + { + _globalOptions = globalOptions; + } public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) - => new CommonWhitespaceSettingsProviderFactory(workspaceServices.Workspace); + => new CommonWhitespaceSettingsProviderFactory(workspaceServices.Workspace, _globalOptions); } } diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Whitespace/View/WhitespaceBoolSettingView.xaml b/src/VisualStudio/Core/Def/EditorConfigSettings/Whitespace/View/WhitespaceBoolSettingView.xaml index 9c00c73c7294d..54c723619f8da 100644 --- a/src/VisualStudio/Core/Def/EditorConfigSettings/Whitespace/View/WhitespaceBoolSettingView.xaml +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Whitespace/View/WhitespaceBoolSettingView.xaml @@ -4,11 +4,147 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:vsshell="clr-namespace:Microsoft.VisualStudio.Shell;assembly=Microsoft.VisualStudio.Shell.15.0" - Resources="{StaticResource {x:Static vsshell:VsResourceKeys.ThemedDialogDefaultStylesKey}}" + xmlns:vs="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Shell.15.0" mc:Ignorable="d" x:ClassModifier="internal"> + + + + + AutomationProperties.Name="{Binding AutomationName}" + FocusVisualStyle="{DynamicResource FocusVisualStyleKey}"> + + + + diff --git a/src/VisualStudio/Core/Def/ExternalAccess/Pythia/PythiaGlobalOptions.cs b/src/VisualStudio/Core/Def/ExternalAccess/Pythia/PythiaGlobalOptions.cs index 5b0e9ba0d7a45..7d508e012f228 100644 --- a/src/VisualStudio/Core/Def/ExternalAccess/Pythia/PythiaGlobalOptions.cs +++ b/src/VisualStudio/Core/Def/ExternalAccess/Pythia/PythiaGlobalOptions.cs @@ -24,23 +24,19 @@ public PythiaGlobalOptions(IGlobalOptionService globalOptions) public bool ShowDebugInfo { get => _globalOptions.GetOption(s_showDebugInfoOption); - set => _globalOptions.SetGlobalOption(new OptionKey(s_showDebugInfoOption), value); + set => _globalOptions.SetGlobalOption(s_showDebugInfoOption, value); } public bool RemoveRecommendationLimit { get => _globalOptions.GetOption(s_removeRecommendationLimitOption); - set => _globalOptions.SetGlobalOption(new OptionKey(s_removeRecommendationLimitOption), value); + set => _globalOptions.SetGlobalOption(s_removeRecommendationLimitOption, value); } - public const string LocalRegistryPath = @"Roslyn\Internal\OnOff\Features\"; - private static readonly Option2 s_showDebugInfoOption = new( - "InternalFeatureOnOffOptions", "ShowDebugInfo", defaultValue: false, - storageLocation: new LocalUserProfileStorageLocation(LocalRegistryPath + "ShowDebugInfo")); + "InternalFeatureOnOffOptions_ShowDebugInfo", defaultValue: false); private static readonly Option2 s_removeRecommendationLimitOption = new( - "InternalFeatureOnOffOptions", "RemoveRecommendationLimit", defaultValue: false, - storageLocation: new LocalUserProfileStorageLocation(LocalRegistryPath + "RemoveRecommendationLimit")); + "InternalFeatureOnOffOptions_RemoveRecommendationLimit", defaultValue: false); } } diff --git a/src/VisualStudio/Core/Def/ExternalAccess/VSTypeScript/Api/VSTypeScriptContainedDocumentWrapper.cs b/src/VisualStudio/Core/Def/ExternalAccess/VSTypeScript/Api/VSTypeScriptContainedDocumentWrapper.cs index 3a8b707fbe3ff..72b895369a4ad 100644 --- a/src/VisualStudio/Core/Def/ExternalAccess/VSTypeScript/Api/VSTypeScriptContainedDocumentWrapper.cs +++ b/src/VisualStudio/Core/Def/ExternalAccess/VSTypeScript/Api/VSTypeScriptContainedDocumentWrapper.cs @@ -45,13 +45,5 @@ public ITextBuffer SubjectBuffer public IVsContainedLanguageHost Host => _underlyingObject.ContainedLanguageHost; - - [Obsolete("Remove once TypeScript has stopped using this.")] - internal AbstractProject Project - => _underlyingObject.Project; - - [Obsolete("Remove once TypeScript has stopped using this.")] - internal IVisualStudioHostDocument HostDocument - => _underlyingObject; } } diff --git a/src/VisualStudio/Core/Def/ExternalAccess/VSTypeScript/Api/VSTypeScriptVisualStudioProjectWrapper.cs b/src/VisualStudio/Core/Def/ExternalAccess/VSTypeScript/Api/VSTypeScriptVisualStudioProjectWrapper.cs index 19918dcdb1617..b4610c7d635c1 100644 --- a/src/VisualStudio/Core/Def/ExternalAccess/VSTypeScript/Api/VSTypeScriptVisualStudioProjectWrapper.cs +++ b/src/VisualStudio/Core/Def/ExternalAccess/VSTypeScript/Api/VSTypeScriptVisualStudioProjectWrapper.cs @@ -4,13 +4,14 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Workspaces.ProjectSystem; using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; namespace Microsoft.VisualStudio.LanguageServices.ExternalAccess.VSTypeScript.Api { internal sealed partial class VSTypeScriptVisualStudioProjectWrapper { - public VSTypeScriptVisualStudioProjectWrapper(VisualStudioProject underlyingObject) + public VSTypeScriptVisualStudioProjectWrapper(ProjectSystemProject underlyingObject) => Project = underlyingObject; public ProjectId Id => Project.Id; @@ -39,6 +40,6 @@ public void RemoveSourceTextContainer(SourceTextContainer sourceTextContainer) public void RemoveFromWorkspace() => Project.RemoveFromWorkspace(); - internal VisualStudioProject Project { get; } + internal ProjectSystemProject Project { get; } } } diff --git a/src/VisualStudio/Core/Def/FindReferences/FindUsagesPresentationOptionsStorage.cs b/src/VisualStudio/Core/Def/FindReferences/FindUsagesPresentationOptionsStorage.cs index 000f3b1447a00..058ee21db9d54 100644 --- a/src/VisualStudio/Core/Def/FindReferences/FindUsagesPresentationOptionsStorage.cs +++ b/src/VisualStudio/Core/Def/FindReferences/FindUsagesPresentationOptionsStorage.cs @@ -8,8 +8,6 @@ namespace Microsoft.VisualStudio.LanguageServices.FindUsages { internal static class FindUsagesPresentationOptionsStorage { - private const string LocalRegistryPath = @"Roslyn\Internal\FindUsages\"; - /// /// Used to store the user's explicit 'grouping priority' for the 'Definition' column. /// We store this because we'll disable this grouping sometimes (i.e. for GoToImplementation), @@ -17,7 +15,6 @@ internal static class FindUsagesPresentationOptionsStorage /// next FindReferences call. /// public static readonly Option2 DefinitionGroupingPriority = new( - "FindUsagesOptions", "DefinitionGroupingPriority", defaultValue: -1, - storageLocation: new LocalUserProfileStorageLocation(LocalRegistryPath + "DefinitionGroupingPriority")); + "FindUsagesOptions_DefinitionGroupingPriority", defaultValue: -1); } } diff --git a/src/VisualStudio/Core/Def/FindReferences/StreamingFindUsagesPresenter.cs b/src/VisualStudio/Core/Def/FindReferences/StreamingFindUsagesPresenter.cs index d260cf44ec2fc..5327da33a2092 100644 --- a/src/VisualStudio/Core/Def/FindReferences/StreamingFindUsagesPresenter.cs +++ b/src/VisualStudio/Core/Def/FindReferences/StreamingFindUsagesPresenter.cs @@ -243,7 +243,7 @@ private AbstractTableDataSourceFindUsagesContext StartSearchWithoutReferences( private void StoreCurrentGroupingPriority(IFindAllReferencesWindow window) { - _globalOptions.SetGlobalOption(new OptionKey(FindUsagesPresentationOptionsStorage.DefinitionGroupingPriority), window.GetDefinitionColumn().GroupingPriority); + _globalOptions.SetGlobalOption(FindUsagesPresentationOptionsStorage.DefinitionGroupingPriority, window.GetDefinitionColumn().GroupingPriority); } private void SetDefinitionGroupingPriority(IFindAllReferencesWindow window, int priority) diff --git a/src/VisualStudio/Core/Def/Implementation/AbstractVsTextViewFilter.cs b/src/VisualStudio/Core/Def/Implementation/AbstractVsTextViewFilter.cs index 07238c1754ebf..e4a5805888030 100644 --- a/src/VisualStudio/Core/Def/Implementation/AbstractVsTextViewFilter.cs +++ b/src/VisualStudio/Core/Def/Implementation/AbstractVsTextViewFilter.cs @@ -235,7 +235,7 @@ internal static int GetPairExtentsWorker(ITextView textView, IBraceMatchingServi { // case a. var closingSpans = braceMatcher.FindMatchingSpanAsync(document, matchingSpan.Value.Start, options, cancellationToken).WaitAndGetResult(cancellationToken); - var vsClosingSpans = textView.GetSpanInView(closingSpans.Value.ToSnapshotSpan(subjectBuffer.CurrentSnapshot)).ToList().First().ToVsTextSpan(); + var vsClosingSpans = textView.GetSpanInView(closingSpans.Value.ToSnapshotSpan(subjectBuffer.CurrentSnapshot)).First().ToVsTextSpan(); pSpan[0].iEndIndex = vsClosingSpans.iStartIndex; } @@ -254,7 +254,7 @@ internal static int GetPairExtentsWorker(ITextView textView, IBraceMatchingServi // case b. var openingSpans = braceMatcher.FindMatchingSpanAsync(document, matchingSpan.Value.End, options, cancellationToken).WaitAndGetResult(cancellationToken); - var vsOpeningSpans = textView.GetSpanInView(openingSpans.Value.ToSnapshotSpan(subjectBuffer.CurrentSnapshot)).ToList().First().ToVsTextSpan(); + var vsOpeningSpans = textView.GetSpanInView(openingSpans.Value.ToSnapshotSpan(subjectBuffer.CurrentSnapshot)).First().ToVsTextSpan(); pSpan[0].iStartIndex = vsOpeningSpans.iStartIndex; } diff --git a/src/VisualStudio/Core/Def/Implementation/ColorSchemes/ColorSchemeOptions.cs b/src/VisualStudio/Core/Def/Implementation/ColorSchemes/ColorSchemeOptions.cs index dffc1ea6e1475..324108609b903 100644 --- a/src/VisualStudio/Core/Def/Implementation/ColorSchemes/ColorSchemeOptions.cs +++ b/src/VisualStudio/Core/Def/Implementation/ColorSchemes/ColorSchemeOptions.cs @@ -11,16 +11,12 @@ internal sealed class ColorSchemeOptions internal const string ColorSchemeSettingKey = "TextEditor.Roslyn.ColorSchemeName"; public static readonly Option2 ColorScheme = new( - "ColorSchemeOptions", - "ColorSchemeName", - defaultValue: ColorSchemeName.VisualStudio2019, - storageLocation: new RoamingProfileStorageLocation(ColorSchemeSettingKey)); + "ColorSchemeOptions_ColorSchemeName", + defaultValue: ColorSchemeName.VisualStudio2019); public static readonly Option2 LegacyUseEnhancedColors = new( - "ColorSchemeOptions", - "LegacyUseEnhancedColors", - defaultValue: UseEnhancedColors.Default, - storageLocation: new RoamingProfileStorageLocation("WindowManagement.Options.UseEnhancedColorsForManagedLanguages")); + "ColorSchemeOptions_LegacyUseEnhancedColors", + defaultValue: UseEnhancedColors.Default); public enum UseEnhancedColors { diff --git a/src/VisualStudio/Core/Def/KeybindingReset/KeybindingResetDetector.cs b/src/VisualStudio/Core/Def/KeybindingReset/KeybindingResetDetector.cs index 871f0f2839974..433d6c1226693 100644 --- a/src/VisualStudio/Core/Def/KeybindingReset/KeybindingResetDetector.cs +++ b/src/VisualStudio/Core/Def/KeybindingReset/KeybindingResetDetector.cs @@ -59,9 +59,9 @@ internal sealed class KeybindingResetDetector : ForegroundThreadAffinitizedObjec private static readonly Guid s_resharperPackageGuid = new("0C6E6407-13FC-4878-869A-C8B4016C57FE"); private static readonly Guid s_resharperCommandGroup = new("47F03277-5055-4922-899C-0F7F30D26BF1"); - private static readonly ImmutableArray s_statusOptions = ImmutableArray.Create( - new OptionKey(KeybindingResetOptions.ReSharperStatus), - new OptionKey(KeybindingResetOptions.NeedsReset)); + private static readonly ImmutableArray s_statusOptions = ImmutableArray.Create( + new OptionKey2(KeybindingResetOptions.ReSharperStatus), + new OptionKey2(KeybindingResetOptions.NeedsReset)); private readonly IGlobalOptionService _globalOptions; private readonly System.IServiceProvider _serviceProvider; @@ -217,7 +217,9 @@ private async Task UpdateStateMachineWorkerAsync(CancellationToken cancellationT break; } - _globalOptions.SetGlobalOptions(s_statusOptions, ImmutableArray.Create(currentStatus, needsReset)); + _globalOptions.SetGlobalOptions(ImmutableArray.Create( + KeyValuePairUtil.Create(new OptionKey2(KeybindingResetOptions.ReSharperStatus), (object)currentStatus), + KeyValuePairUtil.Create(new OptionKey2(KeybindingResetOptions.NeedsReset), (object)needsReset))); if (needsReset) { @@ -351,7 +353,7 @@ private void RestoreVsKeybindings() KeybindingsResetLogger.Log("KeybindingsReset"); - _globalOptions.SetGlobalOption(new OptionKey(KeybindingResetOptions.NeedsReset), false); + _globalOptions.SetGlobalOption(KeybindingResetOptions.NeedsReset, false); } private void OpenExtensionsHyperlink() @@ -361,13 +363,13 @@ private void OpenExtensionsHyperlink() VisualStudioNavigateToLinkService.StartBrowser(KeybindingsFwLink); KeybindingsResetLogger.Log("ExtensionsLink"); - _globalOptions.SetGlobalOption(new OptionKey(KeybindingResetOptions.NeedsReset), false); + _globalOptions.SetGlobalOption(KeybindingResetOptions.NeedsReset, false); } private void NeverShowAgain() { - _globalOptions.SetGlobalOption(new OptionKey(KeybindingResetOptions.NeverShowAgain), true); - _globalOptions.SetGlobalOption(new OptionKey(KeybindingResetOptions.NeedsReset), false); + _globalOptions.SetGlobalOption(KeybindingResetOptions.NeverShowAgain, true); + _globalOptions.SetGlobalOption(KeybindingResetOptions.NeedsReset, false); KeybindingsResetLogger.Log("NeverShowAgain"); // The only external references to this object are as callbacks, which are removed by the Shutdown method. diff --git a/src/VisualStudio/Core/Def/KeybindingReset/KeybindingResetOptions.cs b/src/VisualStudio/Core/Def/KeybindingReset/KeybindingResetOptions.cs index 04a7c55c8f087..10788c4a974ef 100644 --- a/src/VisualStudio/Core/Def/KeybindingReset/KeybindingResetOptions.cs +++ b/src/VisualStudio/Core/Def/KeybindingReset/KeybindingResetOptions.cs @@ -2,33 +2,15 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Collections.Immutable; -using System.Composition; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Options.Providers; namespace Microsoft.VisualStudio.LanguageServices.KeybindingReset { internal sealed class KeybindingResetOptions { - private const string LocalRegistryPath = @"Roslyn\Internal\KeybindingsStatus\"; - - public static readonly Option2 ReSharperStatus = new(nameof(KeybindingResetOptions), - nameof(ReSharperStatus), defaultValue: KeybindingReset.ReSharperStatus.NotInstalledOrDisabled, - storageLocation: new LocalUserProfileStorageLocation(LocalRegistryPath + nameof(ReSharperStatus))); - - public static readonly Option2 NeedsReset = new(nameof(KeybindingResetOptions), - nameof(NeedsReset), defaultValue: false, - storageLocation: new LocalUserProfileStorageLocation(LocalRegistryPath + nameof(NeedsReset))); - - public static readonly Option2 NeverShowAgain = new(nameof(KeybindingResetOptions), - nameof(NeverShowAgain), defaultValue: false, - storageLocation: new LocalUserProfileStorageLocation(LocalRegistryPath + nameof(NeverShowAgain))); - - public static readonly Option2 EnabledFeatureFlag = new(nameof(KeybindingResetOptions), - nameof(EnabledFeatureFlag), defaultValue: false, - storageLocation: new FeatureFlagStorageLocation("Roslyn.KeybindingResetEnabled")); + public static readonly Option2 ReSharperStatus = new("KeybindingResetOptions_ReSharperStatus", defaultValue: KeybindingReset.ReSharperStatus.NotInstalledOrDisabled); + public static readonly Option2 NeedsReset = new("KeybindingResetOptions_NeedsReset", defaultValue: false); + public static readonly Option2 NeverShowAgain = new("KeybindingResetOptions_NeverShowAgain", defaultValue: false); + public static readonly Option2 EnabledFeatureFlag = new("KeybindingResetOptions_EnabledFeatureFlag", defaultValue: false); } } diff --git a/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.IVsContainedLanguageFactory.cs b/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.IVsContainedLanguageFactory.cs index c9cddf2aee538..072ccf9ee8198 100644 --- a/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.IVsContainedLanguageFactory.cs +++ b/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.IVsContainedLanguageFactory.cs @@ -6,6 +6,7 @@ using System; using System.Runtime.InteropServices; +using Microsoft.CodeAnalysis.Workspaces.ProjectSystem; using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.TextManager.Interop; @@ -14,7 +15,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService { internal abstract partial class AbstractLanguageService : IVsContainedLanguageFactory { - private VisualStudioProject FindMatchingProject(IVsHierarchy hierarchy, uint itemid) + private ProjectSystemProject FindMatchingProject(IVsHierarchy hierarchy, uint itemid) { // Here we must determine the project that this file's document is to be a part of. // Venus creates a separate Project for a .aspx or .ascx file, and so we must associate diff --git a/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.cs b/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.cs index c113674a94b9e..3339f0426f026 100644 --- a/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.cs +++ b/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.cs @@ -16,6 +16,7 @@ using Microsoft.CodeAnalysis.Structure; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text.Shared.Extensions; +using Microsoft.CodeAnalysis.Workspaces.ProjectSystem; using Microsoft.VisualStudio.Editor; using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; using Microsoft.VisualStudio.LanguageServices.Implementation.TaskList; @@ -276,7 +277,7 @@ private void UninitializeLanguageDebugInfo() => this.LanguageDebugInfo = null; protected virtual IVsContainedLanguage CreateContainedLanguage( - IVsTextBufferCoordinator bufferCoordinator, VisualStudioProject project, + IVsTextBufferCoordinator bufferCoordinator, ProjectSystemProject project, IVsHierarchy hierarchy, uint itemid) { return new ContainedLanguage( diff --git a/src/VisualStudio/Core/Def/Log/LoggerOptions.cs b/src/VisualStudio/Core/Def/Log/LoggerOptions.cs index 1ba239270d1d6..2854444b47eb8 100644 --- a/src/VisualStudio/Core/Def/Log/LoggerOptions.cs +++ b/src/VisualStudio/Core/Def/Log/LoggerOptions.cs @@ -2,28 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - -using System; -using System.Collections.Immutable; -using System.Composition; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Options.Providers; namespace Microsoft.VisualStudio.LanguageServices.Implementation { internal sealed class LoggerOptions { - private const string LocalRegistryPath = @"Roslyn\Internal\Performance\Logger\"; - - public static readonly Option2 EtwLoggerKey = new(nameof(LoggerOptions), nameof(EtwLoggerKey), defaultValue: true, - storageLocation: new LocalUserProfileStorageLocation(LocalRegistryPath + "EtwLogger")); - - public static readonly Option2 TraceLoggerKey = new(nameof(LoggerOptions), nameof(TraceLoggerKey), defaultValue: false, - storageLocation: new LocalUserProfileStorageLocation(LocalRegistryPath + "TraceLogger")); - - public static readonly Option2 OutputWindowLoggerKey = new(nameof(LoggerOptions), nameof(OutputWindowLoggerKey), defaultValue: false, - storageLocation: new LocalUserProfileStorageLocation(LocalRegistryPath + "OutputWindowLogger")); + public static readonly Option2 EtwLoggerKey = new("LoggerOptions_EtwLoggerKey", defaultValue: true); + public static readonly Option2 TraceLoggerKey = new("LoggerOptions_TraceLoggerKey", defaultValue: false); + public static readonly Option2 OutputWindowLoggerKey = new("LoggerOptions_OutputWindowLoggerKey", defaultValue: false); } } diff --git a/src/VisualStudio/Core/Def/Microsoft.VisualStudio.LanguageServices.csproj b/src/VisualStudio/Core/Def/Microsoft.VisualStudio.LanguageServices.csproj index 7f14f5f1a1827..fdf16ce199c85 100644 --- a/src/VisualStudio/Core/Def/Microsoft.VisualStudio.LanguageServices.csproj +++ b/src/VisualStudio/Core/Def/Microsoft.VisualStudio.LanguageServices.csproj @@ -35,7 +35,6 @@ - diff --git a/src/VisualStudio/Core/Def/NavigateTo/RoslynSearchItemsSource.cs b/src/VisualStudio/Core/Def/NavigateTo/RoslynSearchItemsSource.cs index a74f012aaeb75..b62c5739771cf 100644 --- a/src/VisualStudio/Core/Def/NavigateTo/RoslynSearchItemsSource.cs +++ b/src/VisualStudio/Core/Def/NavigateTo/RoslynSearchItemsSource.cs @@ -22,6 +22,7 @@ private sealed class RoslynSearchItemsSource : CodeSearchItemsSourceBase { private static readonly IImmutableSet s_typeKinds = ImmutableHashSet.Empty .Add(NavigateToItemKind.Class) + .Add(NavigateToItemKind.Enum) .Add(NavigateToItemKind.Structure) .Add(NavigateToItemKind.Interface) .Add(NavigateToItemKind.Delegate) diff --git a/src/VisualStudio/Core/Def/Options/ExportVisualStudioStorageReadFallbackAttribute.cs b/src/VisualStudio/Core/Def/Options/ExportVisualStudioStorageReadFallbackAttribute.cs new file mode 100644 index 0000000000000..1048215d338b4 --- /dev/null +++ b/src/VisualStudio/Core/Def/Options/ExportVisualStudioStorageReadFallbackAttribute.cs @@ -0,0 +1,45 @@ +// 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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis; + +namespace Microsoft.VisualStudio.LanguageServices.Options; + +/// +/// Use this attribute to declare a custom fallback reader for an option stored in Visual Studio storage. +/// +[MetadataAttribute] +[AttributeUsage(AttributeTargets.Class)] +internal sealed class ExportVisualStudioStorageReadFallbackAttribute : ExportAttribute +{ + /// + /// Option unique name. . + /// + public string ConfigName { get; } + + public ExportVisualStudioStorageReadFallbackAttribute(string configName) + : base(typeof(IVisualStudioStorageReadFallback)) + { + ConfigName = configName; + } +} + +internal sealed class OptionNameMetadata +{ + public string ConfigName { get; } + + public OptionNameMetadata(IDictionary data) + => ConfigName = (string)data[nameof(ExportVisualStudioStorageReadFallbackAttribute.ConfigName)]; + + public OptionNameMetadata(string language) + => ConfigName = language; +} diff --git a/src/VisualStudio/Core/Def/Options/FeatureFlagPersister.cs b/src/VisualStudio/Core/Def/Options/FeatureFlagPersister.cs index 6e25e473ed4ea..414c3c305cbd6 100644 --- a/src/VisualStudio/Core/Def/Options/FeatureFlagPersister.cs +++ b/src/VisualStudio/Core/Def/Options/FeatureFlagPersister.cs @@ -10,12 +10,9 @@ using Microsoft.Internal.VisualStudio.Shell.Interop; using Roslyn.Utilities; -namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options +namespace Microsoft.VisualStudio.LanguageServices.Options { - /// - /// Serializes options marked with to the feature flag storage maintained by VS. - /// - internal sealed class FeatureFlagPersister : IOptionPersister + internal sealed class FeatureFlagPersister { private readonly IVsFeatureFlags? _featureFlags; @@ -24,7 +21,7 @@ public FeatureFlagPersister(IVsFeatureFlags? featureFlags) _featureFlags = featureFlags; } - public bool TryFetch(OptionKey optionKey, [NotNullWhen(true)] out object? value) + public bool TryFetch(OptionKey2 optionKey, string flagName, [NotNullWhen(true)] out object? value) { if (_featureFlags == null) { @@ -32,13 +29,6 @@ public bool TryFetch(OptionKey optionKey, [NotNullWhen(true)] out object? value) return false; } - var location = optionKey.Option.StorageLocations.OfType().FirstOrDefault(); - if (location == null) - { - value = null; - return false; - } - if (optionKey.Option.DefaultValue is not bool defaultValue) { throw ExceptionUtilities.UnexpectedValue(optionKey.Option.DefaultValue); @@ -46,7 +36,7 @@ public bool TryFetch(OptionKey optionKey, [NotNullWhen(true)] out object? value) try { - value = _featureFlags.IsFeatureEnabled(location.Name, defaultValue); + value = _featureFlags.IsFeatureEnabled(flagName, defaultValue); } catch (Exception e) when (FatalError.ReportAndCatch(e)) { @@ -56,19 +46,8 @@ public bool TryFetch(OptionKey optionKey, [NotNullWhen(true)] out object? value) return true; } - public bool TryPersist(OptionKey optionKey, object? value) + public void Persist(string flagName, object? value) { - if (_featureFlags == null) - { - return false; - } - - var location = optionKey.Option.StorageLocations.OfType().FirstOrDefault(); - if (location == null) - { - return false; - } - if (value is not bool flag) { throw ExceptionUtilities.UnexpectedValue(value); @@ -76,14 +55,11 @@ public bool TryPersist(OptionKey optionKey, object? value) try { - ((IVsFeatureFlags2)_featureFlags).EnableFeatureFlag(location.Name, flag); + ((IVsFeatureFlags2?)_featureFlags)?.EnableFeatureFlag(flagName, flag); } catch (Exception e) when (FatalError.ReportAndCatch(e)) { - return false; } - - return true; } } } diff --git a/src/VisualStudio/Core/Def/Options/FeatureFlagPersisterProvider.cs b/src/VisualStudio/Core/Def/Options/FeatureFlagPersisterProvider.cs deleted file mode 100644 index d5c0801a245d5..0000000000000 --- a/src/VisualStudio/Core/Def/Options/FeatureFlagPersisterProvider.cs +++ /dev/null @@ -1,52 +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.ComponentModel.Composition; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.ErrorReporting; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; -using Microsoft.Internal.VisualStudio.Shell.Interop; -using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Shell.Interop; - -namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options -{ - [Export(typeof(IOptionPersisterProvider))] - internal sealed class FeatureFlagPersisterProvider : IOptionPersisterProvider - { - private readonly IAsyncServiceProvider _serviceProvider; - private FeatureFlagPersister? _lazyPersister; - - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public FeatureFlagPersisterProvider( - [Import(typeof(SAsyncServiceProvider))] IAsyncServiceProvider serviceProvider) - { - _serviceProvider = serviceProvider; - } - - public async ValueTask GetOrCreatePersisterAsync(CancellationToken cancellationToken) - { - if (_lazyPersister != null) - { - return _lazyPersister; - } - - IVsFeatureFlags? service; - try - { - service = (IVsFeatureFlags?)await _serviceProvider.GetServiceAsync(typeof(SVsFeatureFlags)).ConfigureAwait(false); - } - catch (Exception e) when (FatalError.ReportAndCatch(e)) - { - service = null; - } - - return _lazyPersister = new FeatureFlagPersister(service); - } - } -} diff --git a/src/VisualStudio/Core/Def/Options/IVisualStudioStorageReadFallback.cs b/src/VisualStudio/Core/Def/Options/IVisualStudioStorageReadFallback.cs new file mode 100644 index 0000000000000..a46c7890278fc --- /dev/null +++ b/src/VisualStudio/Core/Def/Options/IVisualStudioStorageReadFallback.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; +using Microsoft.CodeAnalysis; + +namespace Microsoft.VisualStudio.LanguageServices.Options; + +internal delegate Optional TryReadValueDelegate(string storageKey, Type storageType); + +/// +/// Export an implementation of this interface to instruct to read option value +/// from additional storage locations, if it is not found in the primary storage location specified in . +/// This is only necessary for backward compatibility when an option changes the VS storage location or format. +/// +internal interface IVisualStudioStorageReadFallback +{ + Optional TryRead(string? language, TryReadValueDelegate readValue); +} + diff --git a/src/VisualStudio/Core/Def/Options/LocalUserRegistryOptionPersister.cs b/src/VisualStudio/Core/Def/Options/LocalUserRegistryOptionPersister.cs index 551c102147a9a..da16cf6c45a06 100644 --- a/src/VisualStudio/Core/Def/Options/LocalUserRegistryOptionPersister.cs +++ b/src/VisualStudio/Core/Def/Options/LocalUserRegistryOptionPersister.cs @@ -14,12 +14,9 @@ using Microsoft.Win32; using Roslyn.Utilities; -namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options +namespace Microsoft.VisualStudio.LanguageServices.Options { - /// - /// Serializes options marked with to the local hive-specific registry. - /// - internal sealed class LocalUserRegistryOptionPersister : IOptionPersister + internal sealed class LocalUserRegistryOptionPersister { /// /// An object to gate access to . @@ -49,33 +46,8 @@ public static async Task CreateAsync(IAsyncSer return new LocalUserRegistryOptionPersister(root.CreateSubKey(rootPath, RegistryKeyPermissionCheck.ReadWriteSubTree)); } - private static bool TryGetKeyPathAndName(IOption option, [NotNullWhen(true)] out string? path, [NotNullWhen(true)] out string? key) + public bool TryFetch(OptionKey2 optionKey, string path, string key, out object? value) { - var serialization = option.StorageLocations.OfType().SingleOrDefault(); - - if (serialization == null) - { - path = null; - key = null; - return false; - } - else - { - // We'll just use the filesystem APIs to decompose this - path = Path.GetDirectoryName(serialization.KeyName); - key = Path.GetFileName(serialization.KeyName); - return true; - } - } - - bool IOptionPersister.TryFetch(OptionKey optionKey, out object? value) - { - if (!TryGetKeyPathAndName(optionKey.Option, out var path, out var key)) - { - value = null; - return false; - } - lock (_gate) { using var subKey = _registryKey.OpenSubKey(path); @@ -133,6 +105,21 @@ bool IOptionPersister.TryFetch(OptionKey optionKey, out object? value) { // Otherwise we can just store normally value = subKey.GetValue(key, defaultValue: optionKey.Option.DefaultValue); + + if (optionKey.Option.Type.IsEnum) + { + try + { + value = Enum.ToObject(optionKey.Option.Type, value); + } + catch (ArgumentException) + { + // the value may be out of range for the base type of the enum + value = null; + return false; + } + } + return true; } } @@ -141,44 +128,38 @@ bool IOptionPersister.TryFetch(OptionKey optionKey, out object? value) return false; } - bool IOptionPersister.TryPersist(OptionKey optionKey, object? value) + public void Persist(OptionKey2 optionKey, string path, string key, object? value) { - if (_registryKey == null) - { - throw new InvalidOperationException(); - } - - if (!TryGetKeyPathAndName(optionKey.Option, out var path, out var key)) - { - return false; - } + Contract.ThrowIfNull(_registryKey); lock (_gate) { using var subKey = _registryKey.CreateSubKey(path); + var optionType = optionKey.Option.Type; + // Options that are of type bool have to be serialized as integers - if (optionKey.Option.Type == typeof(bool)) + if (optionType == typeof(bool)) { Contract.ThrowIfNull(value); subKey.SetValue(key, (bool)value ? 1 : 0, RegistryValueKind.DWord); - return true; + return; } - if (optionKey.Option.Type == typeof(long)) + if (optionType == typeof(long)) { Contract.ThrowIfNull(value); subKey.SetValue(key, value, RegistryValueKind.QWord); - return true; + return; } - if (optionKey.Option.Type.IsEnum) + if (optionType.IsEnum) { Contract.ThrowIfNull(value); // If the enum is larger than an int, store as a QWord - if (Marshal.SizeOf(Enum.GetUnderlyingType(optionKey.Option.Type)) > Marshal.SizeOf(typeof(int))) + if (Marshal.SizeOf(Enum.GetUnderlyingType(optionType)) > Marshal.SizeOf(typeof(int))) { subKey.SetValue(key, (long)value, RegistryValueKind.QWord); } @@ -187,11 +168,10 @@ bool IOptionPersister.TryPersist(OptionKey optionKey, object? value) subKey.SetValue(key, (int)value, RegistryValueKind.DWord); } - return true; + return; } subKey.SetValue(key, value); - return true; } } } diff --git a/src/VisualStudio/Core/Def/Options/LocalUserRegistryOptionPersisterProvider.cs b/src/VisualStudio/Core/Def/Options/LocalUserRegistryOptionPersisterProvider.cs deleted file mode 100644 index 5baff59982541..0000000000000 --- a/src/VisualStudio/Core/Def/Options/LocalUserRegistryOptionPersisterProvider.cs +++ /dev/null @@ -1,33 +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.ComponentModel.Composition; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; -using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Shell.Interop; -using Roslyn.Utilities; - -namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options -{ - [Export(typeof(IOptionPersisterProvider))] - internal sealed class LocalUserRegistryOptionPersisterProvider : IOptionPersisterProvider - { - private readonly AsyncLazy _lazyPersister; - - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public LocalUserRegistryOptionPersisterProvider( - [Import(typeof(SAsyncServiceProvider))] IAsyncServiceProvider serviceProvider) - { - _lazyPersister = new(_ => LocalUserRegistryOptionPersister.CreateAsync(serviceProvider), cacheResult: true); - } - - public async ValueTask GetOrCreatePersisterAsync(CancellationToken cancellationToken) - => await _lazyPersister.GetValueAsync(cancellationToken).ConfigureAwait(false); - } -} diff --git a/src/VisualStudio/Core/Def/Options/NamingPreferencesReadFallback.cs b/src/VisualStudio/Core/Def/Options/NamingPreferencesReadFallback.cs new file mode 100644 index 0000000000000..2c4336cdfbf29 --- /dev/null +++ b/src/VisualStudio/Core/Def/Options/NamingPreferencesReadFallback.cs @@ -0,0 +1,29 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Composition; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; +using Roslyn.Utilities; +using Microsoft.CodeAnalysis.CodeStyle; + +namespace Microsoft.VisualStudio.LanguageServices.Options; + +[ExportVisualStudioStorageReadFallback(NamingStyleOptions.NamingPreferencesOptionName), Shared] +internal sealed class NamingPreferencesReadFallback : IVisualStudioStorageReadFallback +{ + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public NamingPreferencesReadFallback() + { + } + + public Optional TryRead(string? language, TryReadValueDelegate readValue) + { + Contract.ThrowIfNull(language); + return readValue($"TextEditor.{language}.Specific.NamingPreferences", typeof(NamingStylePreferences)); + } +} diff --git a/src/VisualStudio/Core/Def/Options/PackageSettingsPersister.cs b/src/VisualStudio/Core/Def/Options/PackageSettingsPersister.cs index 66f0f5b8de6ac..5d87fbb8037ef 100644 --- a/src/VisualStudio/Core/Def/Options/PackageSettingsPersister.cs +++ b/src/VisualStudio/Core/Def/Options/PackageSettingsPersister.cs @@ -13,7 +13,7 @@ using Microsoft.VisualStudio.Threading; using Roslyn.Utilities; -namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options +namespace Microsoft.VisualStudio.LanguageServices.Options { internal sealed class PackageSettingsPersister : IOptionPersister { @@ -43,17 +43,17 @@ private async Task InitializeAsync(CancellationToken cancellationToken) _lazyRoslynPackage = await RoslynPackage.GetOrLoadAsync(_threadingContext, _serviceProvider, cancellationToken).ConfigureAwait(true); Assumes.Present(_lazyRoslynPackage); - _optionService.RefreshOption(new OptionKey(SolutionCrawlerOptionsStorage.SolutionBackgroundAnalysisScopeOption), _lazyRoslynPackage.AnalysisScope); + _optionService.RefreshOption(new OptionKey2(SolutionCrawlerOptionsStorage.SolutionBackgroundAnalysisScopeOption), _lazyRoslynPackage.AnalysisScope); _lazyRoslynPackage.AnalysisScopeChanged += OnAnalysisScopeChanged; } private void OnAnalysisScopeChanged(object? sender, EventArgs e) { Assumes.Present(_lazyRoslynPackage); - _optionService.RefreshOption(new OptionKey(SolutionCrawlerOptionsStorage.SolutionBackgroundAnalysisScopeOption), _lazyRoslynPackage.AnalysisScope); + _optionService.RefreshOption(new OptionKey2(SolutionCrawlerOptionsStorage.SolutionBackgroundAnalysisScopeOption), _lazyRoslynPackage.AnalysisScope); } - public bool TryFetch(OptionKey optionKey, out object? value) + public bool TryFetch(OptionKey2 optionKey, out object? value) { // This option is refreshed via the constructor to avoid UI dependencies when retrieving option values. If // we happen to reach this point before the value is available, try to obtain it without blocking, and @@ -67,7 +67,7 @@ public bool TryFetch(OptionKey optionKey, out object? value) } else { - value = SolutionCrawlerOptionsStorage.SolutionBackgroundAnalysisScopeOption.DefaultValue; + value = SolutionCrawlerOptionsStorage.SolutionBackgroundAnalysisScopeOption.Definition.DefaultValue; return true; } } @@ -76,7 +76,7 @@ public bool TryFetch(OptionKey optionKey, out object? value) return false; } - public bool TryPersist(OptionKey optionKey, object? value) + public bool TryPersist(OptionKey2 optionKey, object? value) { if (!Equals(optionKey.Option, SolutionCrawlerOptionsStorage.SolutionBackgroundAnalysisScopeOption)) return false; diff --git a/src/VisualStudio/Core/Def/Options/PackageSettingsPersisterProvider.cs b/src/VisualStudio/Core/Def/Options/PackageSettingsPersisterProvider.cs index c6ec48041770f..2d63bfdedba7b 100644 --- a/src/VisualStudio/Core/Def/Options/PackageSettingsPersisterProvider.cs +++ b/src/VisualStudio/Core/Def/Options/PackageSettingsPersisterProvider.cs @@ -12,7 +12,7 @@ using IAsyncServiceProvider = Microsoft.VisualStudio.Shell.IAsyncServiceProvider; using SAsyncServiceProvider = Microsoft.VisualStudio.Shell.Interop.SAsyncServiceProvider; -namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options +namespace Microsoft.VisualStudio.LanguageServices.Options { [Export(typeof(IOptionPersisterProvider))] internal sealed class PackageSettingsPersisterProvider : IOptionPersisterProvider diff --git a/src/VisualStudio/Core/Def/Options/VisualStudioOptionPersister.cs b/src/VisualStudio/Core/Def/Options/VisualStudioOptionPersister.cs new file mode 100644 index 0000000000000..135d67c3e23b7 --- /dev/null +++ b/src/VisualStudio/Core/Def/Options/VisualStudioOptionPersister.cs @@ -0,0 +1,76 @@ +// 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.ComponentModel; +using System.Diagnostics; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Threading.Tasks; +using System.Xml.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; +using Microsoft.CodeAnalysis.Options; +using Microsoft.VisualStudio.LanguageServices.Setup; +using Microsoft.VisualStudio.Settings; +using Roslyn.Utilities; + +namespace Microsoft.VisualStudio.LanguageServices.Options; + +internal sealed class VisualStudioOptionPersister : IOptionPersister +{ + private readonly VisualStudioSettingsOptionPersister _visualStudioSettingsOptionPersister; + private readonly LocalUserRegistryOptionPersister _localUserRegistryPersister; + private readonly FeatureFlagPersister _featureFlagPersister; + + public VisualStudioOptionPersister( + VisualStudioSettingsOptionPersister visualStudioSettingsOptionPersister, + LocalUserRegistryOptionPersister localUserRegistryPersister, + FeatureFlagPersister featureFlagPersister) + { + _visualStudioSettingsOptionPersister = visualStudioSettingsOptionPersister; + _localUserRegistryPersister = localUserRegistryPersister; + _featureFlagPersister = featureFlagPersister; + } + + public bool TryFetch(OptionKey2 optionKey, out object? value) + { + value = null; + return VisualStudioOptionStorage.Storages.TryGetValue(optionKey.Option.Definition.ConfigName, out var storage) && TryFetch(storage, optionKey, out value); + } + + public bool TryFetch(VisualStudioOptionStorage storage, OptionKey2 optionKey, out object? value) + => storage switch + { + VisualStudioOptionStorage.RoamingProfileStorage roaming => roaming.TryFetch(_visualStudioSettingsOptionPersister, optionKey, out value), + VisualStudioOptionStorage.FeatureFlagStorage featureFlags => featureFlags.TryFetch(_featureFlagPersister, optionKey, out value), + VisualStudioOptionStorage.LocalUserProfileStorage local => local.TryFetch(_localUserRegistryPersister, optionKey, out value), + _ => throw ExceptionUtilities.UnexpectedValue(storage) + }; + + public bool TryPersist(OptionKey2 optionKey, object? value) + { + if (!VisualStudioOptionStorage.Storages.TryGetValue(optionKey.Option.Definition.ConfigName, out var storage)) + { + return false; + } + + // fire and forget: + PersistAsync(storage, optionKey, value).ReportNonFatalErrorAsync(); + return true; + } + + public Task PersistAsync(VisualStudioOptionStorage storage, OptionKey2 optionKey, object? value) + => storage switch + { + VisualStudioOptionStorage.RoamingProfileStorage roaming => roaming.PersistAsync(_visualStudioSettingsOptionPersister, optionKey, value), + VisualStudioOptionStorage.FeatureFlagStorage featureFlags => featureFlags.PersistAsync(_featureFlagPersister, value), + VisualStudioOptionStorage.LocalUserProfileStorage local => local.PersistAsync(_localUserRegistryPersister, optionKey, value), + _ => throw ExceptionUtilities.UnexpectedValue(storage) + }; +} diff --git a/src/VisualStudio/Core/Def/Options/VisualStudioOptionPersisterProvider.cs b/src/VisualStudio/Core/Def/Options/VisualStudioOptionPersisterProvider.cs new file mode 100644 index 0000000000000..3aa03bcd43016 --- /dev/null +++ b/src/VisualStudio/Core/Def/Options/VisualStudioOptionPersisterProvider.cs @@ -0,0 +1,66 @@ +// 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.ComponentModel.Composition; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.ErrorReporting; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; +using Microsoft.Internal.VisualStudio.Shell.Interop; +using Microsoft.VisualStudio.Settings; +using IAsyncServiceProvider = Microsoft.VisualStudio.Shell.IAsyncServiceProvider; +using SAsyncServiceProvider = Microsoft.VisualStudio.Shell.Interop.SAsyncServiceProvider; + +namespace Microsoft.VisualStudio.LanguageServices.Options +{ + [Export(typeof(IOptionPersisterProvider))] + [Export(typeof(VisualStudioOptionPersisterProvider))] + internal sealed class VisualStudioOptionPersisterProvider : IOptionPersisterProvider + { + private readonly IAsyncServiceProvider _serviceProvider; + private readonly ILegacyGlobalOptionService _optionService; + + // maps config name to a read fallback: + private readonly ImmutableDictionary> _readFallbacks; + + private VisualStudioOptionPersister? _lazyPersister; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public VisualStudioOptionPersisterProvider( + [Import(typeof(SAsyncServiceProvider))] IAsyncServiceProvider serviceProvider, + [ImportMany] IEnumerable> readFallbacks, + IThreadingContext threadingContext, + ILegacyGlobalOptionService optionService) + { + _serviceProvider = serviceProvider; + _optionService = optionService; + _readFallbacks = readFallbacks.ToImmutableDictionary(item => item.Metadata.ConfigName, item => item); + } + + public async ValueTask GetOrCreatePersisterAsync(CancellationToken cancellationToken) + => _lazyPersister ??= + new VisualStudioOptionPersister( + new VisualStudioSettingsOptionPersister(_optionService, _readFallbacks, await TryGetServiceAsync().ConfigureAwait(true)), + await LocalUserRegistryOptionPersister.CreateAsync(_serviceProvider).ConfigureAwait(false), + new FeatureFlagPersister(await TryGetServiceAsync().ConfigureAwait(false))); + + private async ValueTask TryGetServiceAsync() where I : class + { + try + { + return (I?)await _serviceProvider.GetServiceAsync(typeof(T)).ConfigureAwait(false); + } + catch (Exception e) when (FatalError.ReportAndCatch(e)) + { + return null; + } + } + } +} diff --git a/src/VisualStudio/Core/Def/Options/VisualStudioOptionStorage.cs b/src/VisualStudio/Core/Def/Options/VisualStudioOptionStorage.cs new file mode 100644 index 0000000000000..41edb2c62739a --- /dev/null +++ b/src/VisualStudio/Core/Def/Options/VisualStudioOptionStorage.cs @@ -0,0 +1,416 @@ +// 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.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Completion; +using Microsoft.CodeAnalysis.Options; +using Microsoft.VisualStudio.Language.Intellisense; +using Roslyn.Utilities; + +namespace Microsoft.VisualStudio.LanguageServices.Options; + +internal abstract class VisualStudioOptionStorage +{ + internal sealed class RoamingProfileStorage : VisualStudioOptionStorage + { + /// + /// Key may contain %LANGUAGE% placeholder that is replaced by the language name. + /// + public string Key { get; } + + /// + /// VB specific key should only be specified for backward compat for a few speciifc options. + /// Language specific storage key should use %LANGUAGE% placeholder in . + /// + public string? VisualBasicKey { get; } + + public RoamingProfileStorage(string key) + { + Key = key; + } + + /// + /// Backward compat only. + /// + [Obsolete] + public RoamingProfileStorage(string key, string vbKey) + { + Key = key; + VisualBasicKey = vbKey; + } + + private string GetKey(string? language) + => (VisualBasicKey != null && language == LanguageNames.VisualBasic) ? VisualBasicKey : SubstituteLanguage(Key, language); + + private static string SubstituteLanguage(string keyName, string? language) + => keyName.Replace("%LANGUAGE%", language switch + { + LanguageNames.CSharp => "CSharp", + LanguageNames.VisualBasic => "VisualBasic", + _ => language // handles F#, TypeScript and Xaml + }); + + public Task PersistAsync(VisualStudioSettingsOptionPersister persister, OptionKey2 optionKey, object? value) + => persister.PersistAsync(optionKey, GetKey(optionKey.Language), value); + + public bool TryFetch(VisualStudioSettingsOptionPersister persister, OptionKey2 optionKey, out object? value) + => persister.TryFetch(optionKey, GetKey(optionKey.Language), out value); + } + + internal sealed class FeatureFlagStorage : VisualStudioOptionStorage + { + public string FlagName { get; } + + public FeatureFlagStorage(string flagName) + { + FlagName = flagName; + } + + public Task PersistAsync(FeatureFlagPersister persister, object? value) + { + persister.Persist(FlagName, value); + return Task.CompletedTask; + } + + public bool TryFetch(FeatureFlagPersister persister, OptionKey2 optionKey, out object? value) + => persister.TryFetch(optionKey, FlagName, out value); + } + + internal sealed class LocalUserProfileStorage : VisualStudioOptionStorage + { + private readonly string _path; + private readonly string _key; + + public LocalUserProfileStorage(string path, string key) + { + _path = path; + _key = key; + } + + public Task PersistAsync(LocalUserRegistryOptionPersister persister, OptionKey2 optionKey, object? 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); + } + + public static readonly IReadOnlyDictionary Storages = new Dictionary() + { + {"BlockStructureOptions_CollapseEmptyMetadataImplementationsWhenFirstOpened", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.CollapseEmptyMetadataImplementationsWhenFirstOpened")}, + {"BlockStructureOptions_CollapseImportsWhenFirstOpened", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.CollapseImportsWhenFirstOpened")}, + {"BlockStructureOptions_CollapseMetadataImplementationsWhenFirstOpened", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.CollapseMetadataImplementationsWhenFirstOpened")}, + {"BlockStructureOptions_CollapseRegionsWhenCollapsingToDefinitions", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.CollapseRegionsWhenCollapsingToDefinitions")}, + {"BlockStructureOptions_CollapseRegionsWhenFirstOpened", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.CollapseRegionsWhenFirstOpened")}, + {"BlockStructureOptions_MaximumBannerLength", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.MaximumBannerLength")}, + {"BlockStructureOptions_ShowBlockStructureGuidesForCodeLevelConstructs", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.ShowBlockStructureGuidesForCodeLevelConstructs")}, + {"BlockStructureOptions_ShowBlockStructureGuidesForCommentsAndPreprocessorRegions", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.ShowBlockStructureGuidesForCommentsAndPreprocessorRegions")}, + {"BlockStructureOptions_ShowBlockStructureGuidesForDeclarationLevelConstructs", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.ShowBlockStructureGuidesForDeclarationLevelConstructs")}, + {"BlockStructureOptions_ShowOutliningForCodeLevelConstructs", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.ShowOutliningForCodeLevelConstructs")}, + {"BlockStructureOptions_ShowOutliningForCommentsAndPreprocessorRegions", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.ShowOutliningForCommentsAndPreprocessorRegions")}, + {"BlockStructureOptions_ShowOutliningForDeclarationLevelConstructs", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.ShowOutliningForDeclarationLevelConstructs")}, + {"BraceCompletionOptions_AutoFormattingOnCloseBrace", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.Auto Formatting On Close Brace")}, + {"ClassificationOptions_ClassifyReassignedVariables", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.ClassificationOptions.ClassifyReassignedVariables")}, + {"CodeStyleOptions_PreferSystemHashCode", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.PreferSystemHashCode")}, + {"ColorSchemeOptions_ColorSchemeName", new RoamingProfileStorage("TextEditor.Roslyn.ColorSchemeName")}, + {"ColorSchemeOptions_LegacyUseEnhancedColors", new RoamingProfileStorage("WindowManagement.Options.UseEnhancedColorsForManagedLanguages")}, + {"CompletionOptions_BlockForCompletionItems", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.BlockForCompletionItems")}, + {"CompletionOptions_EnableArgumentCompletionSnippets", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.EnableArgumentCompletionSnippets")}, + {"CompletionOptions_EnterKeyBehavior", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.EnterKeyBehavior")}, + {"CompletionOptions_HideAdvancedMembers", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Hide Advanced Auto List Members")}, + {"CompletionOptions_HighlightMatchingPortionsOfCompletionListItems", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.HighlightMatchingPortionsOfCompletionListItems")}, + {"CompletionOptions_ShowCompletionItemFilters", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.ShowCompletionItemFilters")}, + {"CompletionOptions_ShowItemsFromUnimportedNamespaces", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.ShowItemsFromUnimportedNamespaces")}, + {"CompletionOptions_ShowNameSuggestions", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.ShowNameSuggestions")}, + {"CompletionOptions_ShowNewSnippetExperienceFeatureFlag", new FeatureFlagStorage(@"Roslyn.SnippetCompletion")}, + {"CompletionOptions_ShowNewSnippetExperienceUserOption", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.ShowNewSnippetExperience")}, + {"CompletionOptions_SnippetsBehavior", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.SnippetsBehavior")}, + {"CompletionOptions_TriggerInArgumentLists", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.TriggerInArgumentLists")}, + {"CompletionOptions_TriggerOnDeletion", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.TriggerOnDeletion")}, + {"CompletionOptions_TriggerOnTyping", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Auto List Members")}, + {"CompletionOptions_TriggerOnTypingLetters", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.TriggerOnTypingLetters")}, + {"CompletionOptions_UnnamedSymbolCompletionDisabledFeatureFlag", new FeatureFlagStorage(@"Roslyn.UnnamedSymbolCompletionDisabled")}, + {"csharp_indent_block_contents", new RoamingProfileStorage("TextEditor.CSharp.Specific.IndentBlock")}, + {"csharp_indent_braces", new RoamingProfileStorage("TextEditor.CSharp.Specific.OpenCloseBracesIndent")}, + {"csharp_indent_case_contents", new RoamingProfileStorage("TextEditor.CSharp.Specific.IndentSwitchCaseSection")}, + {"csharp_indent_case_contents_when_block", new RoamingProfileStorage("TextEditor.CSharp.Specific.IndentSwitchCaseSectionWhenBlock")}, + {"csharp_indent_labels", new RoamingProfileStorage("TextEditor.CSharp.Specific.LabelPositioning")}, + {"csharp_indent_switch_labels", new RoamingProfileStorage("TextEditor.CSharp.Specific.IndentSwitchSection")}, + {"csharp_new_line_before_open_brace", new RoamingProfileStorage("TextEditor.CSharp.Specific.csharp_new_line_before_open_brace") }, + {"csharp_new_line_before_catch", new RoamingProfileStorage("TextEditor.CSharp.Specific.NewLineForCatch")}, + {"csharp_new_line_before_else", new RoamingProfileStorage("TextEditor.CSharp.Specific.NewLineForElse")}, + {"csharp_new_line_before_finally", new RoamingProfileStorage("TextEditor.CSharp.Specific.NewLineForFinally")}, + {"csharp_new_line_before_members_in_anonymous_types", new RoamingProfileStorage("TextEditor.CSharp.Specific.NewLineForMembersInAnonymousTypes")}, + {"csharp_new_line_before_members_in_object_initializers", new RoamingProfileStorage("TextEditor.CSharp.Specific.NewLineForMembersInObjectInit")}, + {"csharp_new_line_between_query_expression_clauses", new RoamingProfileStorage("TextEditor.CSharp.Specific.NewLineForClausesInQuery")}, + {"csharp_prefer_braces", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferBraces")}, + {"csharp_prefer_simple_default_expression", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferSimpleDefaultExpression")}, + {"csharp_prefer_simple_using_statement", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferSimpleUsingStatement")}, + {"csharp_prefer_static_local_function", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferStaticLocalFunction")}, + {"csharp_preferred_modifier_order", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferredModifierOrder")}, + {"csharp_preserve_single_line_blocks", new RoamingProfileStorage("TextEditor.CSharp.Specific.WrappingPreserveSingleLine")}, + {"csharp_preserve_single_line_statements", new RoamingProfileStorage("TextEditor.CSharp.Specific.WrappingKeepStatementsOnSingleLine")}, + {"csharp_space_after_cast", new RoamingProfileStorage("TextEditor.CSharp.Specific.SpaceAfterCast")}, + {"csharp_space_after_colon_in_inheritance_clause", new RoamingProfileStorage("TextEditor.CSharp.Specific.SpaceAfterColonInBaseTypeDeclaration")}, + {"csharp_space_after_comma", new RoamingProfileStorage("TextEditor.CSharp.Specific.SpaceAfterComma")}, + {"csharp_space_after_dot", new RoamingProfileStorage("TextEditor.CSharp.Specific.SpaceAfterDot")}, + {"csharp_space_after_keywords_in_control_flow_statements", new RoamingProfileStorage("TextEditor.CSharp.Specific.SpaceAfterControlFlowStatementKeyword")}, + {"csharp_space_after_semicolon_in_for_statement", new RoamingProfileStorage("TextEditor.CSharp.Specific.SpaceAfterSemicolonsInForStatement")}, + {"csharp_space_around_binary_operators", new RoamingProfileStorage("TextEditor.CSharp.Specific.SpacingAroundBinaryOperator")}, + {"csharp_space_around_declaration_statements", new RoamingProfileStorage("TextEditor.CSharp.Specific.SpacesIgnoreAroundVariableDeclaration")}, + {"csharp_space_before_colon_in_inheritance_clause", new RoamingProfileStorage("TextEditor.CSharp.Specific.SpaceBeforeColonInBaseTypeDeclaration")}, + {"csharp_space_before_comma", new RoamingProfileStorage("TextEditor.CSharp.Specific.SpaceBeforeComma")}, + {"csharp_space_before_dot", new RoamingProfileStorage("TextEditor.CSharp.Specific.SpaceBeforeDot")}, + {"csharp_space_before_open_square_brackets", new RoamingProfileStorage("TextEditor.CSharp.Specific.SpaceBeforeOpenSquareBracket")}, + {"csharp_space_before_semicolon_in_for_statement", new RoamingProfileStorage("TextEditor.CSharp.Specific.SpaceBeforeSemicolonsInForStatement")}, + {"csharp_space_between_empty_square_brackets", new RoamingProfileStorage("TextEditor.CSharp.Specific.SpaceBetweenEmptySquareBrackets")}, + {"csharp_space_between_method_call_empty_parameter_list_parentheses", new RoamingProfileStorage("TextEditor.CSharp.Specific.SpaceBetweenEmptyMethodCallParentheses")}, + {"csharp_space_between_method_call_name_and_opening_parenthesis", new RoamingProfileStorage("TextEditor.CSharp.Specific.SpaceAfterMethodCallName")}, + {"csharp_space_between_method_call_parameter_list_parentheses", new RoamingProfileStorage("TextEditor.CSharp.Specific.SpaceWithinMethodCallParentheses")}, + {"csharp_space_between_method_declaration_empty_parameter_list_parentheses", new RoamingProfileStorage("TextEditor.CSharp.Specific.SpaceBetweenEmptyMethodDeclarationParentheses")}, + {"csharp_space_between_method_declaration_name_and_open_parenthesis", new RoamingProfileStorage("TextEditor.CSharp.Specific.SpacingAfterMethodDeclarationName")}, + {"csharp_space_between_method_declaration_parameter_list_parentheses", new RoamingProfileStorage("TextEditor.CSharp.Specific.SpaceWithinMethodDeclarationParenthesis")}, + {"csharp_space_between_parentheses", new RoamingProfileStorage("TextEditor.CSharp.Specific.csharp_space_between_parentheses") }, + {"csharp_space_between_square_brackets", new RoamingProfileStorage("TextEditor.CSharp.Specific.SpaceWithinSquareBrackets")}, + {"csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental", new RoamingProfileStorage("TextEditor.CSharp.Specific.AllowBlankLineAfterColonInConstructorInitializer")}, + {"csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental", new RoamingProfileStorage("TextEditor.CSharp.Specific.AllowBlankLineAfterTokenInArrowExpressionClause")}, + {"csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental", new RoamingProfileStorage("TextEditor.CSharp.Specific.AllowBlankLineAfterTokenInConditionalExpression")}, + {"csharp_style_allow_blank_lines_between_consecutive_braces_experimental", new RoamingProfileStorage("TextEditor.CSharp.Specific.AllowBlankLinesBetweenConsecutiveBraces")}, + {"csharp_style_allow_embedded_statements_on_same_line_experimental", new RoamingProfileStorage("TextEditor.CSharp.Specific.AllowEmbeddedStatementsOnSameLine")}, + {"csharp_style_conditional_delegate_call", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferConditionalDelegateCall")}, + {"csharp_style_deconstructed_variable_declaration", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferDeconstructedVariableDeclaration")}, + {"csharp_style_expression_bodied_accessors", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferExpressionBodiedAccessors")}, + {"csharp_style_expression_bodied_constructors", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferExpressionBodiedConstructors")}, + {"csharp_style_expression_bodied_indexers", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferExpressionBodiedIndexers")}, + {"csharp_style_expression_bodied_lambdas", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferExpressionBodiedLambdas")}, + {"csharp_style_expression_bodied_local_functions", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferExpressionBodiedLocalFunctions")}, + {"csharp_style_expression_bodied_methods", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferExpressionBodiedMethods")}, + {"csharp_style_expression_bodied_operators", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferExpressionBodiedOperators")}, + {"csharp_style_expression_bodied_properties", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferExpressionBodiedProperties")}, + {"csharp_style_implicit_object_creation_when_type_is_apparent", new RoamingProfileStorage("TextEditor.CSharp.Specific.ImplicitObjectCreationWhenTypeIsApparent")}, + {"csharp_style_inlined_variable_declaration", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferInlinedVariableDeclaration")}, + {"csharp_style_namespace_declarations", new RoamingProfileStorage("TextEditor.CSharp.Specific.NamespaceDeclarations")}, + {"csharp_style_pattern_matching_over_as_with_null_check", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferPatternMatchingOverAsWithNullCheck")}, + {"csharp_style_pattern_matching_over_is_with_cast_check", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferPatternMatchingOverIsWithCastCheck")}, + {"csharp_style_prefer_extended_property_pattern", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferExtendedPropertyPattern")}, + {"csharp_style_prefer_index_operator", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferIndexOperator")}, + {"csharp_style_prefer_local_over_anonymous_function", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferLocalOverAnonymousFunction")}, + {"csharp_style_prefer_method_group_conversion", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferMethodGroupConversion")}, + {"csharp_style_prefer_not_pattern", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferNotPattern")}, + {"csharp_style_prefer_null_check_over_type_check", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferNullCheckOverTypeCheck")}, + {"csharp_style_prefer_pattern_matching", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferPatternMatching")}, + {"csharp_style_prefer_range_operator", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferRangeOperator")}, + {"csharp_style_prefer_readonly_struct", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferReadOnlyStruct")}, + {"csharp_style_prefer_switch_expression", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferSwitchExpression")}, + {"csharp_style_prefer_top_level_statements", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferTopLevelStatements")}, + {"csharp_style_prefer_tuple_swap", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferTupleSwap")}, + {"csharp_style_prefer_utf8_string_literals", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferUtf8StringLiterals")}, + {"csharp_style_throw_expression", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferThrowExpression")}, + {"csharp_style_unused_value_assignment_preference", new RoamingProfileStorage("TextEditor.CSharp.Specific.UnusedValueAssignmentPreference")}, + {"csharp_style_unused_value_expression_statement_preference", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.UnusedValueExpressionStatementPreference")}, + {"csharp_style_var_elsewhere", new RoamingProfileStorage("TextEditor.CSharp.Specific.UseImplicitTypeWherePossible")}, + {"csharp_style_var_for_built_in_types", new RoamingProfileStorage("TextEditor.CSharp.Specific.UseImplicitTypeForIntrinsicTypes")}, + {"csharp_style_var_when_type_is_apparent", new RoamingProfileStorage("TextEditor.CSharp.Specific.UseImplicitTypeWhereApparent")}, + {"csharp_using_directive_placement", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferredUsingDirectivePlacement")}, + {"DateAndTime_ProvideDateAndTimeCompletions", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.ProvideDateAndTimeCompletions")}, + {"DiagnosticOptions_LogTelemetryForBackgroundAnalyzerExecution", new FeatureFlagStorage(@"Roslyn.LogTelemetryForBackgroundAnalyzerExecution")}, + {"DiagnosticOptions_LspPullDiagnosticsFeatureFlag", new FeatureFlagStorage(@"Lsp.PullDiagnostics")}, + {"DiagnosticTaggingOptions_PullDiagnosticTagging", new FeatureFlagStorage(@"Roslyn.PullDiagnosticTagging")}, +#pragma warning disable CS0612 // Type or member is obsolete + {"DocumentationCommentOptions_AutoXmlDocCommentGeneration", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.Automatic XML Doc Comment Generation", "TextEditor.VisualBasic.Specific.AutoComment")}, +#pragma warning restore + {"DocumentOutlineOptions_EnableDocumentOutline", new FeatureFlagStorage(@"Roslyn.DocumentOutline")}, + {"dotnet_code_quality_unused_parameters", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.UnusedParametersPreference")}, + {"dotnet_remove_unnecessary_suppression_exclusions", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.RemoveUnnecessarySuppressionExclusions")}, + {"dotnet_separate_import_directive_groups", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.SeparateImportDirectiveGroups")}, + {"dotnet_sort_system_directives_first", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.PlaceSystemNamespaceFirst")}, + {"dotnet_style_allow_multiple_blank_lines_experimental", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.AllowMultipleBlankLines")}, + {"dotnet_style_allow_statement_immediately_after_block_experimental", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.AllowStatementImmediatelyAfterBlock")}, + {"dotnet_style_coalesce_expression", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.PreferCoalesceExpression")}, + {"dotnet_style_collection_initializer", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.PreferCollectionInitializer")}, + {"dotnet_style_explicit_tuple_names", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.PreferExplicitTupleNames")}, + {"dotnet_style_namespace_match_folder", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.PreferNamespaceAndFolderMatchStructure")}, + {"dotnet_style_null_propagation", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.PreferNullPropagation")}, + {"dotnet_style_object_initializer", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.PreferObjectInitializer")}, + {"dotnet_style_parentheses_in_arithmetic_binary_operators", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.ArithmeticBinaryParenthesesPreference")}, + {"dotnet_style_parentheses_in_other_binary_operators", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.OtherBinaryParenthesesPreference")}, + {"dotnet_style_parentheses_in_other_operators", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.OtherParenthesesPreference")}, + {"dotnet_style_parentheses_in_relational_binary_operators", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.RelationalBinaryParenthesesPreference")}, + {"dotnet_style_predefined_type_for_locals_parameters_members", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.PreferIntrinsicPredefinedTypeKeywordInDeclaration.CodeStyle")}, + {"dotnet_style_predefined_type_for_member_access", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.PreferIntrinsicPredefinedTypeKeywordInMemberAccess.CodeStyle")}, + {"dotnet_style_prefer_auto_properties", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.PreferAutoProperties")}, + {"dotnet_style_prefer_compound_assignment", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.PreferCompoundAssignment")}, + {"dotnet_style_prefer_conditional_expression_over_assignment", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.PreferConditionalExpressionOverAssignment")}, + {"dotnet_style_prefer_conditional_expression_over_return", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.PreferConditionalExpressionOverReturn")}, + {"dotnet_style_prefer_inferred_anonymous_type_member_names", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.PreferInferredAnonymousTypeMemberNames")}, + {"dotnet_style_prefer_inferred_tuple_names", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.PreferInferredTupleNames")}, + {"dotnet_style_prefer_is_null_check_over_reference_equality_method", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.PreferIsNullCheckOverReferenceEqualityMethod")}, + {"dotnet_style_prefer_simplified_boolean_expressions", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.PreferSimplifiedBooleanExpressions")}, + {"dotnet_style_prefer_simplified_interpolation", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.PreferSimplifiedInterpolation")}, + {"dotnet_style_qualification_for_event", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.QualifyEventAccess")}, + {"dotnet_style_qualification_for_field", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.QualifyFieldAccess")}, + {"dotnet_style_qualification_for_method", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.QualifyMethodAccess")}, + {"dotnet_style_qualification_for_property", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.QualifyPropertyAccess")}, + {"dotnet_style_readonly_field", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.PreferReadonly")}, + {"dotnet_style_require_accessibility_modifiers", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.RequireAccessibilityModifiers")}, + {"EditorComponentOnOffOptions_Adornment", new LocalUserProfileStorage(@"Roslyn\Internal\OnOff\Components", "Adornment")}, + {"EditorComponentOnOffOptions_CodeRefactorings", new LocalUserProfileStorage(@"Roslyn\Internal\OnOff\Components", "Code Refactorings")}, + {"EditorComponentOnOffOptions_Tagger", new LocalUserProfileStorage(@"Roslyn\Internal\OnOff\Components", "Tagger")}, + {"ExtractMethodOptions_AllowBestEffort", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.Allow Best Effort")}, + {"ExtractMethodOptions_DontPutOutOrRefOnStruct", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.Don't Put Out Or Ref On Strcut")}, + {"FadingOptions_FadeOutUnreachableCode", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.FadeOutUnreachableCode")}, + {"FadingOptions_FadeOutUnusedImports", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.FadeOutUnusedImports")}, + {"Storage_CloudCacheFeatureFlag", new FeatureFlagStorage(@"Roslyn.CloudCache3")}, + {"Storage_Database", new LocalUserProfileStorage(@"Roslyn\Internal\OnOff\Features", "Database")}, + {"FeatureOnOffOptions_AddImportsOnPaste", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.AddImportsOnPaste2")}, + {"FeatureOnOffOptions_AlwaysUseDefaultSymbolServers", new RoamingProfileStorage("TextEditor.AlwaysUseDefaultSymbolServers")}, + {"FeatureOnOffOptions_AutoInsertBlockCommentStartString", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.Auto Insert Block Comment Start String")}, + {"FeatureOnOffOptions_AutomaticallyCompleteStatementOnSemicolon", new RoamingProfileStorage("TextEditor.AutomaticallyCompleteStatementOnSemicolon")}, + {"FeatureOnOffOptions_AutomaticallyFixStringContentsOnPaste", new RoamingProfileStorage("TextEditor.%LANGUAGE%.AutomaticallyFixStringContentsOnPaste")}, + {"FeatureOnOffOptions_AutomaticInsertionOfAbstractOrInterfaceMembers", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.AutoRequiredMemberInsert")}, + {"FeatureOnOffOptions_EndConstruct", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.AutoEndInsert")}, + {"FeatureOnOffOptions_InheritanceMarginCombinedWithIndicatorMargin", new RoamingProfileStorage("TextEditor.InheritanceMarginCombinedWithIndicatorMargin")}, + {"FeatureOnOffOptions_InheritanceMarginIncludeGlobalImports", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.InheritanceMarginIncludeGlobalImports")}, +#pragma warning disable CS0612 // Type or member is obsolete + {"FeatureOnOffOptions_KeywordHighlighting", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.Keyword Highlighting", "TextEditor.VisualBasic.Specific.EnableHighlightRelatedKeywords")}, + {"FeatureOnOffOptions_LineSeparator", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.Line Separator", "TextEditor.VisualBasic.Specific.DisplayLineSeparators")}, +#pragma warning restore + {"FeatureOnOffOptions_NavigateAsynchronously", new RoamingProfileStorage("TextEditor.NavigateAsynchronously")}, + {"FeatureOnOffOptions_NavigateToDecompiledSources", new RoamingProfileStorage("TextEditor.NavigateToDecompiledSources")}, + {"FeatureOnOffOptions_NavigateToSourceLinkAndEmbeddedSources", new RoamingProfileStorage("TextEditor.NavigateToSourceLinkAndEmbeddedSources")}, + {"FeatureOnOffOptions_OfferRemoveUnusedReferences", new RoamingProfileStorage("TextEditor.OfferRemoveUnusedReferences")}, + {"FeatureOnOffOptions_OfferRemoveUnusedReferencesFeatureFlag", new FeatureFlagStorage(@"Roslyn.RemoveUnusedReferences")}, + {"FeatureOnOffOptions_Outlining", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.Outlining")}, + {"FeatureOnOffOptions_PrettyListing", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.PrettyListing")}, +#pragma warning disable CS0612 // Type or member is obsolete + {"FeatureOnOffOptions_ReferenceHighlighting", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.Reference Highlighting", "TextEditor.VisualBasic.Specific.EnableHighlightReferences")}, + {"FeatureOnOffOptions_RenameTrackingPreview", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.Rename Tracking Preview", "TextEditor.VisualBasic.Specific.RenameTrackingPreview")}, +#pragma warning restore + {"FeatureOnOffOptions_ShowInheritanceMargin", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.ShowInheritanceMargin")}, + {"FeatureOnOffOptions_SkipAnalyzersForImplicitlyTriggeredBuilds", new RoamingProfileStorage("TextEditor.SkipAnalyzersForImplicitlyTriggeredBuilds")}, + {"FeatureOnOffOptions_StringIdentation", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.StringIdentation")}, + {"FindUsagesOptions_DefinitionGroupingPriority", new LocalUserProfileStorage(@"Roslyn\Internal\FindUsages", "DefinitionGroupingPriority")}, + {"FormattingOptions_AutoFormattingOnReturn", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.Auto Formatting On Return")}, + {"FormattingOptions_AutoFormattingOnSemicolon", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.Auto Formatting On Semicolon")}, + {"FormattingOptions_AutoFormattingOnTyping", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.Auto Formatting On Typing")}, + {"FormattingOptions_FormatOnPaste", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.FormatOnPaste")}, + {"FormattingOptions_SmartIndent", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Indent Style")}, + {"GenerateConstructorFromMembersOptions_AddNullChecks", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.GenerateConstructorFromMembersOptions.AddNullChecks")}, + {"GenerateEqualsAndGetHashCodeFromMembersOptions_GenerateOperators", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.GenerateEqualsAndGetHashCodeFromMembersOptions.GenerateOperators")}, + {"GenerateEqualsAndGetHashCodeFromMembersOptions_ImplementIEquatable", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.GenerateEqualsAndGetHashCodeFromMembersOptions.ImplementIEquatable")}, + {"GenerateOverridesOptions_SelectAll", new RoamingProfileStorage("TextEditor.Specific.GenerateOverridesOptions.SelectAll")}, + {"ImplementTypeOptions_InsertionBehavior", new RoamingProfileStorage("TextEditor.%LANGUAGE%.ImplementTypeOptions.InsertionBehavior")}, + {"ImplementTypeOptions_PropertyGenerationBehavior", new RoamingProfileStorage("TextEditor.%LANGUAGE%.ImplementTypeOptions.PropertyGenerationBehavior")}, + {"indent_size", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Indent Size")}, + {"indent_style", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Insert Tabs")}, + {"InlineDiagnosticsOptions_EnableInlineDiagnostics", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.InlineDiagnostics")}, + {"InlineDiagnosticsOptions_Location", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.InlineDiagnostics.LocationOption")}, + {"InlineHintsOptions_ColorHints", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.ColorHints")}, + {"InlineHintsOptions_DisplayAllHintsWhilePressingAltF1", new RoamingProfileStorage("TextEditor.Specific.DisplayAllHintsWhilePressingAltF1")}, + {"InlineHintsOptions_EnabledForParameters", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.InlineParameterNameHints")}, + {"InlineHintsOptions_EnabledForTypes", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.InlineTypeHints")}, + {"InlineHintsOptions_ForImplicitObjectCreation", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.InlineTypeHints.ForImplicitObjectCreation")}, + {"InlineHintsOptions_ForImplicitVariableTypes", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.InlineTypeHints.ForImplicitVariableTypes")}, + {"InlineHintsOptions_ForIndexerParameters", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.InlineParameterNameHints.ForArrayIndexers")}, + {"InlineHintsOptions_ForLambdaParameterTypes", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.InlineTypeHints.ForLambdaParameterTypes")}, + {"InlineHintsOptions_ForLiteralParameters", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.InlineParameterNameHints.ForLiteralParameters")}, + {"InlineHintsOptions_ForObjectCreationParameters", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.InlineParameterNameHints.ForObjectCreationParameters")}, + {"InlineHintsOptions_ForOtherParameters", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.InlineParameterNameHints.ForOtherParameters")}, + {"InlineHintsOptions_SuppressForParametersThatDifferOnlyBySuffix", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.InlineParameterNameHints.SuppressForParametersThatDifferOnlyBySuffix")}, + {"InlineHintsOptions_SuppressForParametersThatMatchArgumentName", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.InlineParameterNameHints.SuppressForParametersThatMatchArgumentName")}, + {"InlineHintsOptions_SuppressForParametersThatMatchMethodIntent", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.InlineParameterNameHints.SuppressForParametersThatMatchMethodIntent")}, + {"InlineRename_CollapseRenameUI", new RoamingProfileStorage("TextEditor.CollapseRenameUI")}, + {"InlineRename_UseInlineAdornment", new RoamingProfileStorage("TextEditor.RenameUseInlineAdornment")}, + {"InlineRenameSessionOptions_PreviewChanges", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.PreviewRename")}, + {"InlineRenameSessionOptions_RenameAsynchronously", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.RenameAsynchronously")}, + {"InlineRenameSessionOptions_RenameFile", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.RenameFile")}, + {"InlineRenameSessionOptions_RenameInComments", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.RenameInComments")}, + {"InlineRenameSessionOptions_RenameInStrings", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.RenameInStrings")}, + {"InlineRenameSessionOptions_RenameOverloads", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.RenameOverloads")}, + {"InternalDiagnosticsOptions_CrashOnAnalyzerException", new LocalUserProfileStorage(@"Roslyn\Internal\Diagnostics", "CrashOnAnalyzerException")}, + {"InternalDiagnosticsOptions_EnableFileLoggingForDiagnostics", new LocalUserProfileStorage(@"Roslyn\Internal\Diagnostics", "EnableFileLoggingForDiagnostics")}, + {"InternalDiagnosticsOptions_NormalDiagnosticMode", new LocalUserProfileStorage(@"Roslyn\Internal\Diagnostics", "NormalDiagnosticMode")}, + {"InternalFeatureOnOffOptions_AutomaticLineEnder", new LocalUserProfileStorage(@"Roslyn\Internal\OnOff\Features", "Automatic Line Ender")}, + {"InternalFeatureOnOffOptions_BraceMatching", new LocalUserProfileStorage(@"Roslyn\Internal\OnOff\Features", "Brace Matching")}, + {"InternalFeatureOnOffOptions_Classification", new LocalUserProfileStorage(@"Roslyn\Internal\OnOff\Features", "Classification")}, + {"InternalFeatureOnOffOptions_EventHookup", new LocalUserProfileStorage(@"Roslyn\Internal\OnOff\Features", "Event Hookup")}, + {"InternalFeatureOnOffOptions_FormatOnSave", new LocalUserProfileStorage(@"Roslyn\Internal\OnOff\Features", "FormatOnSave")}, + {"InternalFeatureOnOffOptions_FullSolutionAnalysisMemoryMonitor", new LocalUserProfileStorage(@"Roslyn\Internal\OnOff\Features", "Full Solution Analysis Memory Monitor")}, + {"InternalFeatureOnOffOptions_OOP64Bit", new LocalUserProfileStorage(@"Roslyn\Internal\OnOff\Features", "OOP64Bit")}, + {"InternalFeatureOnOffOptions_OOPCoreClrFeatureFlag", new FeatureFlagStorage(@"Roslyn.ServiceHubCore")}, + {"InternalFeatureOnOffOptions_OOPServerGCFeatureFlag", new FeatureFlagStorage(@"Roslyn.OOPServerGC")}, + {"InternalFeatureOnOffOptions_RemoveRecommendationLimit", new LocalUserProfileStorage(@"Roslyn\Internal\OnOff\Features", "RemoveRecommendationLimit")}, + {"InternalFeatureOnOffOptions_RenameTracking", new LocalUserProfileStorage(@"Roslyn\Internal\OnOff\Features", "Rename Tracking")}, + {"InternalFeatureOnOffOptions_SemanticColorizer", new LocalUserProfileStorage(@"Roslyn\Internal\OnOff\Features", "Semantic Colorizer")}, + {"InternalFeatureOnOffOptions_ShowDebugInfo", new LocalUserProfileStorage(@"Roslyn\Internal\OnOff\Features", "ShowDebugInfo")}, + {"InternalFeatureOnOffOptions_SmartIndenter", new LocalUserProfileStorage(@"Roslyn\Internal\OnOff\Features", "Smart Indenter")}, + {"InternalFeatureOnOffOptions_Snippets", new LocalUserProfileStorage(@"Roslyn\Internal\OnOff\Features", "Snippets2")}, + {"InternalFeatureOnOffOptions_Squiggles", new LocalUserProfileStorage(@"Roslyn\Internal\OnOff\Features", "Squiggles")}, + {"InternalFeatureOnOffOptions_SyntacticColorizer", new LocalUserProfileStorage(@"Roslyn\Internal\OnOff\Features", "Syntactic Colorizer")}, + {"InternalSolutionCrawlerOptions_Solution Crawler", new LocalUserProfileStorage(@"Roslyn\Internal\SolutionCrawler", "Solution Crawler")}, + {"JsonFeatureOptions_ColorizeJsonPatterns", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.ColorizeJsonPatterns")}, + {"JsonFeatureOptions_DetectAndOfferEditorFeaturesForProbableJsonStrings", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.DetectAndOfferEditorFeaturesForProbableJsonStrings")}, + {"JsonFeatureOptions_HighlightRelatedJsonComponentsUnderCursor", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.HighlightRelatedJsonComponentsUnderCursor")}, + {"JsonFeatureOptions_ReportInvalidJsonPatterns", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.ReportInvalidJsonPatterns")}, + {"KeybindingResetOptions_EnabledFeatureFlag", new FeatureFlagStorage(@"Roslyn.KeybindingResetEnabled")}, + {"KeybindingResetOptions_NeedsReset", new LocalUserProfileStorage(@"Roslyn\Internal\KeybindingsStatus", "NeedsReset")}, + {"KeybindingResetOptions_NeverShowAgain", new LocalUserProfileStorage(@"Roslyn\Internal\KeybindingsStatus", "NeverShowAgain")}, + {"KeybindingResetOptions_ReSharperStatus", new LocalUserProfileStorage(@"Roslyn\Internal\KeybindingsStatus", "ReSharperStatus")}, + {"LoggerOptions_EtwLoggerKey", new LocalUserProfileStorage(@"Roslyn\Internal\Performance\Logger", "EtwLogger")}, + {"LoggerOptions_OutputWindowLoggerKey", new LocalUserProfileStorage(@"Roslyn\Internal\Performance\Logger", "OutputWindowLogger")}, + {"LoggerOptions_TraceLoggerKey", new LocalUserProfileStorage(@"Roslyn\Internal\Performance\Logger", "TraceLogger")}, + {"LspOptions_LspEditorFeatureFlag", new FeatureFlagStorage(@"Roslyn.LSP.Editor")}, + {"LspOptions_LspSemanticTokensFeatureFlag", new FeatureFlagStorage(@"Roslyn.LSP.SemanticTokens")}, + {"LspOptions_MaxCompletionListSize", new LocalUserProfileStorage(@"Roslyn\Internal\Lsp", "MaxCompletionListSize")}, + {"NavigationBarOptions_ShowNavigationBar", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Dropdown Bar")}, + {"QuickInfoOptions_IncludeNavigationHintsInQuickInfo", new RoamingProfileStorage("TextEditor.Specific.IncludeNavigationHintsInQuickInfo")}, + {"QuickInfoOptions_ShowRemarksInQuickInfo", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.ShowRemarks")}, + {"RegularExpressionsOptions_ColorizeRegexPatterns", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.ColorizeRegexPatterns")}, + {"RegularExpressionsOptions_HighlightRelatedRegexComponentsUnderCursor", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.HighlightRelatedRegexComponentsUnderCursor")}, + {"RegularExpressionsOptions_ProvideRegexCompletions", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.ProvideRegexCompletions")}, + {"RegularExpressionsOptions_ReportInvalidRegexPatterns", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.ReportInvalidRegexPatterns")}, + {"ServiceFeatureOnOffOptions_RemoveDocumentDiagnosticsOnDocumentClose", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.RemoveDocumentDiagnosticsOnDocumentClose")}, + {"SignatureHelpOptions_ShowSignatureHelp", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Auto List Params")}, + {"SimplificationOptions_NamingPreferences", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.NamingPreferences5")}, + {"SolutionCrawlerOptionsStorage_BackgroundAnalysisScopeOption", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.BackgroundAnalysisScopeOption")}, + {"SolutionCrawlerOptionsStorage_CompilerDiagnosticsScopeOption", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.CompilerDiagnosticsScopeOption")}, + {"SplitCommentOptions_Enabled", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.SplitComments")}, + {"SplitStringLiteralOptions_Enabled", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.SplitStringLiterals")}, + {"StackTraceExplorerOptions_OpenOnFocus", new RoamingProfileStorage("StackTraceExplorer.Options.OpenOnFocus")}, + {"SuggestionsOptions_Asynchronous", new RoamingProfileStorage("TextEditor.Specific.Suggestions.Asynchronous4")}, + {"SuggestionsOptions_AsynchronousQuickActionsDisableFeatureFlag", new FeatureFlagStorage(@"Roslyn.AsynchronousQuickActionsDisable2")}, + {"SymbolSearchOptions_Enabled", new LocalUserProfileStorage(@"Roslyn\Features\SymbolSearch", "Enabled")}, + {"SymbolSearchOptions_SuggestForTypesInNuGetPackages", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.SuggestForTypesInNuGetPackages")}, + {"SymbolSearchOptions_SuggestForTypesInReferenceAssemblies", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.SuggestForTypesInReferenceAssemblies")}, + {"tab_width", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Tab Size")}, + {"TaskListOptionsStorage_ComputeTaskListItemsForClosedFiles", new RoamingProfileStorage("TextEditor.Specific.ComputeTaskListItemsForClosedFiles")}, + {"TaskListOptionsStorage_Descriptors", new RoamingProfileStorage("Microsoft.VisualStudio.ErrorListPkg.Shims.TaskListOptions.CommentTokens")}, + {"UseConditionalExpressionOptions_ConditionalExpressionWrappingLength", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.ConditionalExpressionWrappingLength")}, + {"ValidateFormatStringOption_ReportInvalidPlaceholdersInStringDotFormatCalls", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.WarnOnInvalidStringDotFormatCalls")}, + {"visual_basic_preferred_modifier_order", new RoamingProfileStorage("TextEditor.VisualBasic.Specific.PreferredModifierOrder")}, + {"visual_basic_style_prefer_isnot_expression", new RoamingProfileStorage("TextEditor.VisualBasic.Specific.PreferIsNotExpression")}, + {"visual_basic_style_prefer_simplified_object_creation", new RoamingProfileStorage("TextEditor.VisualBasic.Specific.PreferSimplifiedObjectCreation")}, + {"visual_basic_style_unused_value_assignment_preference", new RoamingProfileStorage("TextEditor.VisualBasic.Specific.UnusedValueAssignmentPreference")}, + {"visual_basic_style_unused_value_expression_statement_preference", new RoamingProfileStorage("TextEditor.VisualBasic.Specific.UnusedValueExpressionStatementPreference")}, + {"VisualStudioNavigationOptions_NavigateToObjectBrowser", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.NavigateToObjectBrowser")}, + {"VisualStudioWorkspaceStatusService_PartialLoadModeFeatureFlag", new FeatureFlagStorage(@"Roslyn.PartialLoadMode")}, + {"WorkspaceConfigurationOptions_DisableBackgroundCompilation", new FeatureFlagStorage(@"Roslyn.DisableBackgroundCompilation")}, + {"WorkspaceConfigurationOptions_DisableReferenceManagerRecoverableMetadata", new FeatureFlagStorage(@"Roslyn.DisableReferenceManagerRecoverableMetadata")}, + {"WorkspaceConfigurationOptions_DisableSharedSyntaxTrees", new FeatureFlagStorage(@"Roslyn.DisableSharedSyntaxTrees")}, + {"WorkspaceConfigurationOptions_EnableDiagnosticsInSourceGeneratedFiles", new RoamingProfileStorage("TextEditor.Roslyn.Specific.EnableDiagnosticsInSourceGeneratedFilesExperiment")}, + {"WorkspaceConfigurationOptions_EnableDiagnosticsInSourceGeneratedFilesFeatureFlag", new FeatureFlagStorage(@"Roslyn.EnableDiagnosticsInSourceGeneratedFiles")}, + {"WorkspaceConfigurationOptions_EnableOpeningSourceGeneratedFilesInWorkspace", new RoamingProfileStorage("TextEditor.Roslyn.Specific.EnableOpeningSourceGeneratedFilesInWorkspaceExperiment")}, + {"WorkspaceConfigurationOptions_EnableOpeningSourceGeneratedFilesInWorkspaceFeatureFlag", new FeatureFlagStorage(@"Roslyn.SourceGeneratorsEnableOpeningInWorkspace")}, + {"XamlOptions_EnableLspIntelliSenseFeatureFlag", new FeatureFlagStorage(@"Xaml.EnableLspIntelliSense")}, + }; +} diff --git a/src/VisualStudio/Core/Def/Options/VisualStudioSettingsOptionPersister.cs b/src/VisualStudio/Core/Def/Options/VisualStudioSettingsOptionPersister.cs index c444acee8fac4..ea067638d84a6 100644 --- a/src/VisualStudio/Core/Def/Options/VisualStudioSettingsOptionPersister.cs +++ b/src/VisualStudio/Core/Def/Options/VisualStudioSettingsOptionPersister.cs @@ -10,7 +10,9 @@ using System.Linq; using System.Reflection; using System.Runtime.InteropServices; +using System.Threading.Tasks; using System.Xml.Linq; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; using Microsoft.CodeAnalysis.Options; @@ -18,37 +20,38 @@ using Microsoft.VisualStudio.Settings; using Roslyn.Utilities; -namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options +namespace Microsoft.VisualStudio.LanguageServices.Options { /// - /// Serializes settings marked with to and from VS Settings storage. + /// Serializes settings to and from VS Settings storage. /// - internal sealed class VisualStudioSettingsOptionPersister : IOptionPersister + internal sealed class VisualStudioSettingsOptionPersister { // 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 { }; private readonly ISettingsManager? _settingManager; - private readonly IGlobalOptionService _globalOptionService; + private readonly ILegacyGlobalOptionService _legacyGlobalOptions; + private readonly ImmutableDictionary> _readFallbacks; /// - /// The list of options that have been been fetched from , by key. We track this so - /// if a later change happens, we know to refresh that value. This is synchronized with monitor locks on - /// . + /// Options that have been been fetched from , by key. We track this so + /// if a later change happens, we know to refresh that value. /// - private readonly Dictionary> _optionsToMonitorForChanges = new(); - private readonly object _optionsToMonitorForChangesGate = new(); + private ImmutableDictionary _optionsToMonitorForChanges + = ImmutableDictionary.Empty; /// /// We make sure this code is from the UI by asking for all in /// - public VisualStudioSettingsOptionPersister(IGlobalOptionService globalOptionService, ISettingsManager? settingsManager) + public VisualStudioSettingsOptionPersister(ILegacyGlobalOptionService globalOptionService, ImmutableDictionary> readFallbacks, ISettingsManager? settingsManager) { Contract.ThrowIfNull(globalOptionService); _settingManager = settingsManager; - _globalOptionService = globalOptionService; + _legacyGlobalOptions = globalOptionService; + _readFallbacks = readFallbacks; // While the settings persistence service should be available in all SKUs it is possible an ISO shell author has undefined the // contributing package. In that case persistence of settings won't work (we don't bother with a backup solution for persistence @@ -60,216 +63,119 @@ public VisualStudioSettingsOptionPersister(IGlobalOptionService globalOptionServ } } - private System.Threading.Tasks.Task OnSettingChangedAsync(object sender, PropertyChangedEventArgs args) + private Task OnSettingChangedAsync(object sender, PropertyChangedEventArgs args) { - List? optionsToRefresh = null; - - lock (_optionsToMonitorForChangesGate) - { - if (_optionsToMonitorForChanges.TryGetValue(args.PropertyName, out var optionsToRefreshInsideLock)) - { - // Make a copy of the list so we aren't using something that might mutate underneath us. - optionsToRefresh = optionsToRefreshInsideLock.ToList(); - } - } - - if (optionsToRefresh != null) + var storageKey = args.PropertyName; + if (_optionsToMonitorForChanges.TryGetValue(storageKey, out var entry)) { - // Refresh the actual options outside of our _optionsToMonitorForChangesGate so we avoid any deadlocks by calling back - // into the global option service under our lock. There isn't some race here where if we were fetching an option for the first time - // while the setting was changed we might not refresh it. Why? We call RecordObservedValueToWatchForChanges before we fetch the value - // and since this event is raised after the setting is modified, any new setting would have already been observed in GetFirstOrDefaultValue. - // And if it wasn't, this event will then refresh it. - foreach (var optionToRefresh in optionsToRefresh) + var optionValue = TryReadOptionValue(entry.optionKey, storageKey, entry.storageType); + if (optionValue.HasValue && _legacyGlobalOptions.GlobalOptions.RefreshOption(entry.optionKey, optionValue.Value)) { - if (TryFetch(optionToRefresh, out var optionValue)) - { - _globalOptionService.RefreshOption(optionToRefresh, optionValue); - } + // We may be updating the values of internally defined public options. + // Update solution snapshots of all workspaces to reflect the new values. + _legacyGlobalOptions.UpdateRegisteredWorkspaces(); } } - return System.Threading.Tasks.Task.CompletedTask; + return Task.CompletedTask; } - private object? GetFirstOrDefaultValue(OptionKey optionKey, IEnumerable storageLocations) + private void RecordObservedValueToWatchForChanges(OptionKey2 optionKey, string storageKey, Type storageType) { - Contract.ThrowIfNull(_settingManager); - - // There can be more than 1 storage location in the order of their priority. - // When fetching a value, we iterate all of them until we find the first one that exists. - // When persisting a value, we always use the first location. - // This functionality exists to accomodate breaking changes to persistence of some options. In such a case, there - // will be a new location added to the beginning with a new name. When fetching a value, we might find the old - // location (and can upgrade the value accordingly) but we only write to the new location so that - // we don't interfere with older versions. This will essentially "fork" the user's options at the time of upgrade. + ImmutableInterlocked.GetOrAdd(ref _optionsToMonitorForChanges, storageKey, _ => (optionKey, storageType)); + } - foreach (var storageLocation in storageLocations) + public bool TryFetch(OptionKey2 optionKey, string storageKey, out object? value) + { + var result = TryReadOptionValue(optionKey, storageKey, optionKey.Option.Type); + if (result.HasValue) { - var storageKey = storageLocation.GetKeyNameForLanguage(optionKey.Language); - - RecordObservedValueToWatchForChanges(optionKey, storageKey); - - if (optionKey.Option.Type == typeof(ImmutableArray) && - _settingManager.TryGetValue(storageKey, out string[] stringArray) == GetValueResult.Success) - { - return stringArray.ToImmutableArray(); - } - - if (optionKey.Option.Type == typeof(int) && - _settingManager.TryGetValue(storageKey, out int intValue) == GetValueResult.Success) - { - return intValue; - } + value = result.Value; + return true; + } - if (_settingManager.TryGetValue(storageKey, out object value) == GetValueResult.Success) + if (_readFallbacks.TryGetValue(optionKey.Option.Definition.ConfigName, out var lazyReadFallback)) + { + var fallbackResult = lazyReadFallback.Value.TryRead(optionKey.Language, (storageKey, storageType) => TryReadOptionValue(optionKey, storageKey, storageType)); + if (fallbackResult.HasValue) { - return value; + value = fallbackResult.Value; + return true; } } - return optionKey.Option.DefaultValue; + value = null; + return false; } - public bool TryFetch(OptionKey optionKey, out object? value) + public Optional TryReadOptionValue(OptionKey2 optionKey, string storageKey, Type storageType) { - if (_settingManager == null) + Contract.ThrowIfNull(_settingManager); + + RecordObservedValueToWatchForChanges(optionKey, storageKey, storageType); + + if (storageType == typeof(bool) && _settingManager.TryGetValue(storageKey, out bool boolValue) == GetValueResult.Success) { - Debug.Fail("Manager field is unexpectedly null."); - value = null; - return false; + return boolValue; } - var storageLocations = optionKey.Option.StorageLocations.OfType(); - if (!storageLocations.Any()) + if (storageType == typeof(bool?) && _settingManager.TryGetValue(storageKey, out bool? nullableBoolValue) == GetValueResult.Success) { - value = null; - return false; + return nullableBoolValue; } - value = GetFirstOrDefaultValue(optionKey, storageLocations); - - // VS's ISettingsManager has some quirks around storing enums. Specifically, - // it *can* persist and retrieve enums, but only if you properly call - // GetValueOrDefault. This is because it actually stores enums just - // as ints and depends on the type parameter passed in to convert the integral - // value back to an enum value. Unfortunately, we call GetValueOrDefault - // and so we get the value back as boxed integer. - // - // Because of that, manually convert the integer to an enum here so we don't - // crash later trying to cast a boxed integer to an enum value. - if (optionKey.Option.Type.IsEnum) + if (storageType == typeof(int) && _settingManager.TryGetValue(storageKey, out int intValue) == GetValueResult.Success) { - if (value != null) - { - value = Enum.ToObject(optionKey.Option.Type, value); - } + return intValue; } - else if (typeof(ICodeStyleOption).IsAssignableFrom(optionKey.Option.Type)) + + if (storageType.IsEnum && _settingManager.TryGetValue(storageKey, out int enumValue) == GetValueResult.Success) { - return DeserializeCodeStyleOption(ref value, optionKey.Option.Type); + return Enum.ToObject(storageType, enumValue); } - else if (optionKey.Option.Type == typeof(NamingStylePreferences)) + + if (storageType == typeof(NamingStylePreferences) || typeof(ICodeStyleOption).IsAssignableFrom(storageType)) { - // We store these as strings, so deserialize - if (value is string serializedValue) + if (_settingManager.TryGetValue(storageKey, out string stringValue) == GetValueResult.Success) { try { - value = NamingStylePreferences.FromXElement(XElement.Parse(serializedValue)); + if (storageType == typeof(NamingStylePreferences)) + { + return NamingStylePreferences.FromXElement(XElement.Parse(stringValue)); + } + else + { + var fromXElement = storageType.GetMethod(nameof(CodeStyleOption.FromXElement), BindingFlags.Public | BindingFlags.Static); + return fromXElement.Invoke(null, new object[] { XElement.Parse(stringValue) }); + } } - catch (Exception) + catch { - value = null; - return false; + return default; } } - else - { - value = null; - return false; - } - } - else if (optionKey.Option.Type == typeof(bool) && value is int intValue) - { - // TypeScript used to store some booleans as integers. We now handle them properly for legacy sync scenarios. - value = intValue != 0; - return true; - } - else if (optionKey.Option.Type == typeof(bool) && value is long longValue) - { - // TypeScript used to store some booleans as integers. We now handle them properly for legacy sync scenarios. - value = longValue != 0; - return true; - } - else if (optionKey.Option.Type == typeof(bool?)) - { - // code uses object to hold onto any value which will use boxing on value types. - // see boxing on nullable types - https://msdn.microsoft.com/en-us/library/ms228597.aspx - return value is bool or null; - } - else if (value != null && optionKey.Option.Type != value.GetType()) - { - // We got something back different than we expected, so fail to deserialize - value = null; - return false; } - return true; - } - - private static bool DeserializeCodeStyleOption(ref object? value, Type type) - { - if (value is string serializedValue) + if (storageType == typeof(ImmutableArray) && _settingManager.TryGetValue(storageKey, out string[] stringArray) == GetValueResult.Success) { - try - { - var fromXElement = type.GetMethod(nameof(CodeStyleOption.FromXElement), BindingFlags.Public | BindingFlags.Static); - - value = fromXElement.Invoke(null, new object[] { XElement.Parse(serializedValue) }); - return true; - } - catch (Exception) - { - } + return stringArray.ToImmutableArray(); } - value = null; - return false; - } - - private void RecordObservedValueToWatchForChanges(OptionKey optionKey, string storageKey) - { - // We're about to fetch the value, so make sure that if it changes we'll know about it - lock (_optionsToMonitorForChangesGate) + if (_settingManager.TryGetValue(storageKey, out object? value) == GetValueResult.Success && + (value is null || value.GetType() == storageType)) { - var optionKeysToMonitor = _optionsToMonitorForChanges.GetOrAdd(storageKey, _ => new List()); - - if (!optionKeysToMonitor.Contains(optionKey)) - { - optionKeysToMonitor.Add(optionKey); - } + return value; } + + return default; } - public bool TryPersist(OptionKey optionKey, object? value) + public Task PersistAsync(OptionKey2 optionKey, string storageKey, object? value) { - if (_settingManager == null) - { - Debug.Fail("Manager field is unexpectedly null."); - return false; - } - - // Do we roam this at all? - var storageLocation = optionKey.Option.StorageLocations.OfType().FirstOrDefault(); - if (storageLocation == null) - { - return false; - } - - var storageKey = storageLocation.GetKeyNameForLanguage(optionKey.Language); + Contract.ThrowIfNull(_settingManager); - RecordObservedValueToWatchForChanges(optionKey, storageKey); + RecordObservedValueToWatchForChanges(optionKey, storageKey, optionKey.Option.Type); if (value is ICodeStyleOption codeStyleOption) { @@ -284,9 +190,12 @@ public bool TryPersist(OptionKey optionKey, object? value) value = valueToSerialize.CreateXElement().ToString(); } } + else if (value is ImmutableArray stringArray) + { + value = stringArray.IsDefault ? null : stringArray.ToArray(); + } - _settingManager.SetValueAsync(storageKey, value, storageLocation.IsMachineLocal); - return true; + return _settingManager.SetValueAsync(storageKey, value, isMachineLocal: false); } } } diff --git a/src/VisualStudio/Core/Def/Options/VisualStudioSettingsOptionPersisterProvider.cs b/src/VisualStudio/Core/Def/Options/VisualStudioSettingsOptionPersisterProvider.cs deleted file mode 100644 index 79970bbae5ce3..0000000000000 --- a/src/VisualStudio/Core/Def/Options/VisualStudioSettingsOptionPersisterProvider.cs +++ /dev/null @@ -1,49 +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.ComponentModel.Composition; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.Shared.Utilities; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; -using Microsoft.Internal.VisualStudio.Shell.Interop; -using Microsoft.VisualStudio.Settings; -using IAsyncServiceProvider = Microsoft.VisualStudio.Shell.IAsyncServiceProvider; -using SAsyncServiceProvider = Microsoft.VisualStudio.Shell.Interop.SAsyncServiceProvider; - -namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options -{ - [Export(typeof(IOptionPersisterProvider))] - internal sealed class VisualStudioSettingsOptionPersisterProvider : IOptionPersisterProvider - { - private readonly IAsyncServiceProvider _serviceProvider; - private readonly IGlobalOptionService _optionService; - private VisualStudioSettingsOptionPersister? _lazyPersister; - - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public VisualStudioSettingsOptionPersisterProvider( - [Import(typeof(SAsyncServiceProvider))] IAsyncServiceProvider serviceProvider, - IGlobalOptionService optionService) - { - _serviceProvider = serviceProvider; - _optionService = optionService; - } - - public async ValueTask GetOrCreatePersisterAsync(CancellationToken cancellationToken) - { - if (_lazyPersister is not null) - { - return _lazyPersister; - } - - var settingsManager = (ISettingsManager?)await _serviceProvider.GetServiceAsync(typeof(SVsSettingsPersistenceManager)).ConfigureAwait(true); - - _lazyPersister ??= new VisualStudioSettingsOptionPersister(_optionService, settingsManager); - return _lazyPersister; - } - } -} diff --git a/src/VisualStudio/Core/Def/Options/XamlOptions.cs b/src/VisualStudio/Core/Def/Options/XamlOptions.cs index 801721deba258..7201865871edc 100644 --- a/src/VisualStudio/Core/Def/Options/XamlOptions.cs +++ b/src/VisualStudio/Core/Def/Options/XamlOptions.cs @@ -2,12 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Collections.Immutable; -using System.Composition; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Options.Providers; namespace Microsoft.CodeAnalysis.Editor.Xaml { @@ -20,9 +15,6 @@ namespace Microsoft.CodeAnalysis.Editor.Xaml /// internal sealed class XamlOptions { - private const string FeatureName = "XamlOptions"; - - public static readonly Option2 EnableLspIntelliSenseFeatureFlag = new(FeatureName, nameof(EnableLspIntelliSenseFeatureFlag), defaultValue: false, - new FeatureFlagStorageLocation("Xaml.EnableLspIntelliSense")); + public static readonly Option2 EnableLspIntelliSenseFeatureFlag = new("XamlOptions_EnableLspIntelliSenseFeatureFlag", defaultValue: false); } } diff --git a/src/VisualStudio/Core/Def/ProjectSystem/AbstractProject.cs b/src/VisualStudio/Core/Def/ProjectSystem/AbstractProject.cs deleted file mode 100644 index 7c3b2e5036177..0000000000000 --- a/src/VisualStudio/Core/Def/ProjectSystem/AbstractProject.cs +++ /dev/null @@ -1,248 +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.Collections.Immutable; -using System.IO; -using System.Linq; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Editor.Shared.Utilities; -using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.Text; -using Microsoft.VisualStudio.LanguageServices.Implementation.CodeModel; -using Microsoft.VisualStudio.LanguageServices.Implementation.TaskList; -using Microsoft.VisualStudio.LanguageServices.Implementation.Venus; -using Microsoft.VisualStudio.Shell.Interop; -using Microsoft.VisualStudio.TextManager.Interop; -using Roslyn.Utilities; - -namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem -{ - using Workspace = Microsoft.CodeAnalysis.Workspace; - - [Obsolete("This is a compatibility shim for TypeScript; please do not use it.")] - internal abstract partial class AbstractProject : ForegroundThreadAffinitizedObject, IVisualStudioHostProject - { - internal const string ProjectGuidPropertyName = "ProjectGuid"; - - private string _displayName; - private readonly VisualStudioWorkspace _visualStudioWorkspace; - - public AbstractProject( - VisualStudioProjectTracker projectTracker, - Func reportExternalErrorCreatorOpt, - string projectSystemName, - string projectFilePath, - IVsHierarchy hierarchy, - string language, - Guid projectGuid, -#pragma warning disable IDE0060 // Remove unused parameter - not used, but left for compat with TypeScript - IServiceProvider serviceProviderNotUsed, -#pragma warning restore IDE0060 // Remove unused parameter - VisualStudioWorkspaceImpl workspace, - HostDiagnosticUpdateSource hostDiagnosticUpdateSourceOpt, -#pragma warning disable IDE0060 // Remove unused parameter - not used, but left for compat - ICommandLineParserService commandLineParserServiceOpt = null) -#pragma warning restore IDE0060 // Remove unused parameter - : base(projectTracker.ThreadingContext) - { - Hierarchy = hierarchy; - Guid = projectGuid; - Language = language; - ProjectTracker = projectTracker; - _visualStudioWorkspace = workspace; - - this.DisplayName = hierarchy != null && hierarchy.TryGetName(out var name) ? name : projectSystemName; - - ProjectSystemName = projectSystemName; - HostDiagnosticUpdateSource = hostDiagnosticUpdateSourceOpt; - - // Set the default value for last design time build result to be true, until the project system lets us know that it failed. - LastDesignTimeBuildSucceeded = true; - - if (projectFilePath != null && File.Exists(projectFilePath)) - { - ProjectFilePath = projectFilePath; - } - - if (ProjectFilePath != null) - { - Version = VersionStamp.Create(File.GetLastWriteTimeUtc(ProjectFilePath)); - } - else - { - Version = VersionStamp.Create(); - } - - if (reportExternalErrorCreatorOpt != null) - { - ExternalErrorReporter = reportExternalErrorCreatorOpt(Id); - } - } - - /// - /// A full path to the project bin output binary, or null if the project doesn't have an bin output binary. - /// - // FYI: this can't be made virtual because there are calls to this where a 'call' instead of 'callvirt' is being used to call - // the method. - internal string BinOutputPath => GetOutputFilePath(); - - protected virtual string GetOutputFilePath() - => VisualStudioProject.OutputFilePath; - - protected IVsReportExternalErrors ExternalErrorReporter { get; } - - internal HostDiagnosticUpdateSource HostDiagnosticUpdateSource { get; } - - public virtual ProjectId Id => VisualStudioProject?.Id ?? ExplicitId; - - internal ProjectId ExplicitId { get; set; } - - public string Language { get; } - public VisualStudioProjectTracker ProjectTracker { get; } - - /// - /// The for this project. NOTE: May be null in Deferred Project Load cases. - /// - public IVsHierarchy Hierarchy { get; } - - /// - /// Guid of the project - /// - /// it is not readonly since it can be changed while loading project - /// - public Guid Guid { get; protected set; } - - public Workspace Workspace { get; } - - public VersionStamp Version { get; } - - public IProjectCodeModel ProjectCodeModel { get; protected set; } - - /// - /// The containing directory of the project. Null if none exists (consider Venus.) - /// - protected string ContainingDirectoryPathOpt - { - get - { - var projectFilePath = this.ProjectFilePath; - if (projectFilePath != null) - { - return Path.GetDirectoryName(projectFilePath); - } - else - { - return null; - } - } - } - - /// - /// The full path of the project file. Null if none exists (consider Venus.) - /// Note that the project file path might change with project file rename. - /// If you need the folder of the project, just use which doesn't change for a project. - /// - public string ProjectFilePath { get; private set; } - - /// - /// The public display name of the project. This name is not unique and may be shared - /// between multiple projects, especially in cases like Venus where the intellisense - /// projects will match the name of their logical parent project. - /// - public string DisplayName - { - get => _displayName; - set - { - _displayName = value; - - UpdateVisualStudioProjectProperties(); - } - } - - internal string AssemblyName { get; private set; } - - /// - /// The name of the project according to the project system. In "regular" projects this is - /// equivalent to , but in Venus cases these will differ. The - /// ProjectSystemName is the 2_Default.aspx project name, whereas the regular display name - /// matches the display name of the project the user actually sees in the solution explorer. - /// These can be assumed to be unique within the Visual Studio workspace. - /// - public string ProjectSystemName { get; } - - /// - /// Flag indicating if the latest design time build has succeeded for current project state. - /// - /// Default value is true. - protected bool LastDesignTimeBuildSucceeded { get; private set; } - -#nullable enable - - public VisualStudioProject? VisualStudioProject { get; internal set; } - -#nullable disable - - internal void UpdateVisualStudioProjectProperties() - { - if (VisualStudioProject != null) - { - VisualStudioProject.DisplayName = this.DisplayName; - } - } - - [Obsolete("This is a compatibility shim for TypeScript; please do not use it.")] - protected void UpdateProjectDisplayName(string displayName) - => this.DisplayName = displayName; - - [Obsolete("This is a compatibility shim for TypeScript; please do not use it.")] - internal void AddDocument(IVisualStudioHostDocument document, bool isCurrentContext, bool hookupHandlers) - { - var shimDocument = (DocumentProvider.ShimDocument)document; - - VisualStudioProject.AddSourceFile(shimDocument.FilePath, shimDocument.SourceCodeKind); - } - - [Obsolete("This is a compatibility shim for TypeScript; please do not use it.")] - internal void RemoveDocument(IVisualStudioHostDocument document) - { - var containedDocument = ContainedDocument.TryGetContainedDocument(document.Id); - if (containedDocument != null) - { - VisualStudioProject.RemoveSourceTextContainer(containedDocument.SubjectBuffer.AsTextContainer()); - containedDocument.Dispose(); - } - else - { - var shimDocument = (DocumentProvider.ShimDocument)document; - VisualStudioProject.RemoveSourceFile(shimDocument.FilePath); - } - } - - [Obsolete("This is a compatibility shim for TypeScript; please do not use it.")] - internal IVisualStudioHostDocument GetCurrentDocumentFromPath(string filePath) - { - var id = _visualStudioWorkspace.CurrentSolution.GetDocumentIdsWithFilePath(filePath).FirstOrDefault(d => d.ProjectId == Id); - - if (id != null) - { - return new DocumentProvider.ShimDocument(this, id, filePath); - } - else - { - return null; - } - } - - [Obsolete("This is a compatibility shim for TypeScript; please do not use it.")] - internal ImmutableArray GetCurrentDocuments() - { - return _visualStudioWorkspace.CurrentSolution.GetProject(Id).Documents.SelectAsArray( - d => (IVisualStudioHostDocument)new DocumentProvider.ShimDocument(this, d.Id, d.FilePath, d.SourceCodeKind)); - } - } -} diff --git a/src/VisualStudio/Core/Def/ProjectSystem/BrokeredService/WorkspaceProject.cs b/src/VisualStudio/Core/Def/ProjectSystem/BrokeredService/WorkspaceProject.cs index 01d0a6ee86e2f..e3ea9d9c06dbd 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/BrokeredService/WorkspaceProject.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/BrokeredService/WorkspaceProject.cs @@ -118,6 +118,22 @@ public async Task RemoveSourceFilesAsync(IReadOnlyList sourceFiles, Canc _project.RemoveSourceFile(sourceFile); } + public async Task AddDynamicFilesAsync(IReadOnlyList dynamicFilePaths, CancellationToken cancellationToken) + { + await using var batch = _project.CreateBatchScope().ConfigureAwait(false); + + foreach (var dynamicFilePath in dynamicFilePaths) + _project.AddDynamicFile(dynamicFilePath); + } + + public async Task RemoveDynamicFilesAsync(IReadOnlyList dynamicFilePaths, CancellationToken cancellationToken) + { + await using var batch = _project.CreateBatchScope().ConfigureAwait(false); + + foreach (var dynamicFilePath in dynamicFilePaths) + _project.RemoveDynamicFile(dynamicFilePath); + } + public async Task SetBuildSystemPropertiesAsync(IReadOnlyDictionary properties, CancellationToken cancellationToken) { await using var batch = _project.CreateBatchScope().ConfigureAwait(false); @@ -138,6 +154,12 @@ public Task SetDisplayNameAsync(string displayName, CancellationToken cancellati return Task.CompletedTask; } + public Task SetProjectHasAllInformationAsync(bool hasAllInformation, CancellationToken cancellationToken) + { + _project.LastDesignTimeBuildSucceeded = hasAllInformation; + return Task.CompletedTask; + } + public Task StartBatchAsync(CancellationToken cancellationToken) { return Task.FromResult(_project.CreateBatchScope()); diff --git a/src/VisualStudio/Core/Def/ProjectSystem/DocumentProvider.cs b/src/VisualStudio/Core/Def/ProjectSystem/DocumentProvider.cs deleted file mode 100644 index 52fd01f102639..0000000000000 --- a/src/VisualStudio/Core/Def/ProjectSystem/DocumentProvider.cs +++ /dev/null @@ -1,40 +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.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Text; -using Microsoft.VisualStudio.Text; - -namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem -{ - [Obsolete("This is a compatibility shim for TypeScript; please do not use it.")] - internal sealed class DocumentProvider - { - internal class ShimDocument : IVisualStudioHostDocument - { - public ShimDocument(AbstractProject hostProject, DocumentId id, string filePath, SourceCodeKind sourceCodeKind = SourceCodeKind.Regular) - { - Project = hostProject; - Id = id ?? DocumentId.CreateNewId(hostProject.Id, filePath); - FilePath = filePath; - SourceCodeKind = sourceCodeKind; - } - - public AbstractProject Project { get; } - - public DocumentId Id { get; } - - public string FilePath { get; } - - public SourceCodeKind SourceCodeKind { get; } - } - } -} diff --git a/src/VisualStudio/Core/Def/ProjectSystem/IVisualStudioHostDocument.cs b/src/VisualStudio/Core/Def/ProjectSystem/IVisualStudioHostDocument.cs deleted file mode 100644 index a6c7b6e802092..0000000000000 --- a/src/VisualStudio/Core/Def/ProjectSystem/IVisualStudioHostDocument.cs +++ /dev/null @@ -1,25 +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.Collections.Generic; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Text; -using Microsoft.VisualStudio.Shell.Interop; -using Microsoft.VisualStudio.Text; -using Microsoft.VisualStudio.Text.Operations; - -namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem -{ - [Obsolete("This is a compatibility shim for TypeScript; please do not use it.")] - internal interface IVisualStudioHostDocument - { - /// - /// The workspace document Id for this document. - /// - DocumentId Id { get; } - } -} diff --git a/src/VisualStudio/Core/Def/ProjectSystem/IVisualStudioHostProject.cs b/src/VisualStudio/Core/Def/ProjectSystem/IVisualStudioHostProject.cs deleted file mode 100644 index 6746811f9f735..0000000000000 --- a/src/VisualStudio/Core/Def/ProjectSystem/IVisualStudioHostProject.cs +++ /dev/null @@ -1,17 +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; - -namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem -{ - [Obsolete("This is a compatibility shim for TypeScript; please do not use it.")] - internal interface IVisualStudioHostProject - { - ProjectId Id { get; } - } -} diff --git a/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject.cs b/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject.cs index bca7a6ba1cfee..0543999160655 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject.cs @@ -12,6 +12,7 @@ using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Workspaces.ProjectSystem; using Microsoft.VisualStudio.ComponentModelHost; using Microsoft.VisualStudio.LanguageServices.Implementation.CodeModel; using Microsoft.VisualStudio.LanguageServices.Implementation.TaskList; @@ -29,12 +30,12 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.L internal abstract partial class AbstractLegacyProject : ForegroundThreadAffinitizedObject { public IVsHierarchy Hierarchy { get; } - protected VisualStudioProject VisualStudioProject { get; } + protected ProjectSystemProject ProjectSystemProject { get; } internal VisualStudioProjectOptionsProcessor VisualStudioProjectOptionsProcessor { get; set; } protected IProjectCodeModel ProjectCodeModel { get; set; } protected VisualStudioWorkspace Workspace { get; } - internal VisualStudioProject Test_VisualStudioProject => VisualStudioProject; + internal ProjectSystemProject Test_ProjectSystemProject => ProjectSystemProject; /// /// The path to the directory of the project. Read-only, since although you can rename @@ -102,7 +103,7 @@ public AbstractLegacyProject( } var projectFactory = componentModel.GetService(); - VisualStudioProject = threadingContext.JoinableTaskFactory.Run(() => projectFactory.CreateAndAddToWorkspaceAsync( + ProjectSystemProject = threadingContext.JoinableTaskFactory.Run(() => projectFactory.CreateAndAddToWorkspaceAsync( projectSystemName, language, new VisualStudioProjectCreationInfo @@ -117,7 +118,7 @@ public AbstractLegacyProject( CancellationToken.None)); workspaceImpl.AddProjectRuleSetFileToInternalMaps( - VisualStudioProject, + ProjectSystemProject, () => VisualStudioProjectOptionsProcessor.EffectiveRuleSetFilePath); // Right now VB doesn't have the concept of "default namespace". But we conjure one in workspace @@ -125,44 +126,44 @@ public AbstractLegacyProject( // use it for their own purpose. // In the future, we might consider officially exposing "default namespace" for VB project // (e.g. through a msbuild property) - VisualStudioProject.DefaultNamespace = GetRootNamespacePropertyValue(hierarchy); + ProjectSystemProject.DefaultNamespace = GetRootNamespacePropertyValue(hierarchy); if (TryGetPropertyValue(hierarchy, BuildPropertyNames.MaxSupportedLangVersion, out var maxLangVer)) { - VisualStudioProject.MaxLangVersion = maxLangVer; + ProjectSystemProject.MaxLangVersion = maxLangVer; } if (TryGetBoolPropertyValue(hierarchy, BuildPropertyNames.RunAnalyzers, out var runAnayzers)) { - VisualStudioProject.RunAnalyzers = runAnayzers; + ProjectSystemProject.RunAnalyzers = runAnayzers; } if (TryGetBoolPropertyValue(hierarchy, BuildPropertyNames.RunAnalyzersDuringLiveAnalysis, out var runAnayzersDuringLiveAnalysis)) { - VisualStudioProject.RunAnalyzersDuringLiveAnalysis = runAnayzersDuringLiveAnalysis; + ProjectSystemProject.RunAnalyzersDuringLiveAnalysis = runAnayzersDuringLiveAnalysis; } Hierarchy = hierarchy; ConnectHierarchyEvents(); RefreshBinOutputPath(); - _externalErrorReporter = new ProjectExternalErrorReporter(VisualStudioProject.Id, externalErrorReportingPrefix, language, workspaceImpl); + _externalErrorReporter = new ProjectExternalErrorReporter(ProjectSystemProject.Id, externalErrorReportingPrefix, language, workspaceImpl); _batchScopeCreator = componentModel.GetService(); - _batchScopeCreator.StartTrackingProject(VisualStudioProject, Hierarchy); + _batchScopeCreator.StartTrackingProject(ProjectSystemProject, Hierarchy); } - public string AssemblyName => VisualStudioProject.AssemblyName; + public string AssemblyName => ProjectSystemProject.AssemblyName; public string GetOutputFileName() - => VisualStudioProject.CompilationOutputAssemblyFilePath; + => ProjectSystemProject.CompilationOutputAssemblyFilePath; public virtual void Disconnect() { - _batchScopeCreator.StopTrackingProject(VisualStudioProject); + _batchScopeCreator.StopTrackingProject(ProjectSystemProject); VisualStudioProjectOptionsProcessor?.Dispose(); ProjectCodeModel.OnProjectClosed(); - VisualStudioProject.RemoveFromWorkspace(); + ProjectSystemProject.RemoveFromWorkspace(); // Unsubscribe IVsHierarchyEvents DisconnectHierarchyEvents(); @@ -190,7 +191,7 @@ protected void AddFile( folders = GetFolderNamesForDocument(itemid); } - VisualStudioProject.AddSourceFile(filename, sourceCodeKind, folders); + ProjectSystemProject.AddSourceFile(filename, sourceCodeKind, folders); } protected void AddFile( @@ -212,14 +213,14 @@ protected void AddFile( var linkFolderPath = Path.GetDirectoryName(linkMetadata); folders = linkFolderPath.Split(PathSeparatorCharacters, StringSplitOptions.RemoveEmptyEntries).ToImmutableArray(); } - else if (!string.IsNullOrEmpty(VisualStudioProject.FilePath)) + else if (!string.IsNullOrEmpty(ProjectSystemProject.FilePath)) { var relativePath = PathUtilities.GetRelativePath(_projectDirectory, filename); var relativePathParts = relativePath.Split(PathSeparatorCharacters); folders = ImmutableArray.Create(relativePathParts, start: 0, length: relativePathParts.Length - 1); } - VisualStudioProject.AddSourceFile(filename, sourceCodeKind, folders); + ProjectSystemProject.AddSourceFile(filename, sourceCodeKind, folders); } protected void RemoveFile(string filename) @@ -232,7 +233,7 @@ protected void RemoveFile(string filename) return; } - VisualStudioProject.RemoveSourceFile(filename); + ProjectSystemProject.RemoveSourceFile(filename); ProjectCodeModel.OnSourceFileRemoved(filename); } @@ -266,12 +267,12 @@ protected void RefreshBinOutputPath() // web app case if (!PathUtilities.IsAbsolute(outputDirectory)) { - if (VisualStudioProject.FilePath == null) + if (ProjectSystemProject.FilePath == null) { return; } - outputDirectory = FileUtilities.ResolveRelativePath(outputDirectory, Path.GetDirectoryName(VisualStudioProject.FilePath)); + outputDirectory = FileUtilities.ResolveRelativePath(outputDirectory, Path.GetDirectoryName(ProjectSystemProject.FilePath)); } if (outputDirectory == null) @@ -279,15 +280,15 @@ protected void RefreshBinOutputPath() return; } - VisualStudioProject.OutputFilePath = FileUtilities.NormalizeAbsolutePath(Path.Combine(outputDirectory, targetFileName)); + ProjectSystemProject.OutputFilePath = FileUtilities.NormalizeAbsolutePath(Path.Combine(outputDirectory, targetFileName)); if (ErrorHandler.Succeeded(storage.GetPropertyValue("TargetRefPath", null, (uint)_PersistStorageType.PST_PROJECT_FILE, out var targetRefPath)) && !string.IsNullOrEmpty(targetRefPath)) { - VisualStudioProject.OutputRefFilePath = targetRefPath; + ProjectSystemProject.OutputRefFilePath = targetRefPath; } else { - VisualStudioProject.OutputRefFilePath = null; + ProjectSystemProject.OutputRefFilePath = null; } } diff --git a/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject_IAnalyzerConfigFileHost.cs b/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject_IAnalyzerConfigFileHost.cs index 6f482fe229e5e..d76b697e2a228 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject_IAnalyzerConfigFileHost.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject_IAnalyzerConfigFileHost.cs @@ -11,9 +11,9 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.L internal abstract partial class AbstractLegacyProject : IAnalyzerConfigFileHost { void IAnalyzerConfigFileHost.AddAnalyzerConfigFile(string filePath) - => VisualStudioProject.AddAnalyzerConfigFile(filePath); + => ProjectSystemProject.AddAnalyzerConfigFile(filePath); void IAnalyzerConfigFileHost.RemoveAnalyzerConfigFile(string filePath) - => VisualStudioProject.RemoveAnalyzerConfigFile(filePath); + => ProjectSystemProject.RemoveAnalyzerConfigFile(filePath); } } diff --git a/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject_IAnalyzerHost.cs b/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject_IAnalyzerHost.cs index 2ad93728581c6..a402c829cea41 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject_IAnalyzerHost.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject_IAnalyzerHost.cs @@ -13,10 +13,10 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.L internal abstract partial class AbstractLegacyProject : IAnalyzerHost { void IAnalyzerHost.AddAnalyzerReference(string analyzerAssemblyFullPath) - => VisualStudioProject.AddAnalyzerReference(analyzerAssemblyFullPath); + => ProjectSystemProject.AddAnalyzerReference(analyzerAssemblyFullPath); void IAnalyzerHost.RemoveAnalyzerReference(string analyzerAssemblyFullPath) - => VisualStudioProject.RemoveAnalyzerReference(analyzerAssemblyFullPath); + => ProjectSystemProject.RemoveAnalyzerReference(analyzerAssemblyFullPath); void IAnalyzerHost.SetRuleSetFile(string ruleSetFileFullPath) { @@ -36,9 +36,9 @@ void IAnalyzerHost.SetRuleSetFile(string ruleSetFileFullPath) } void IAnalyzerHost.AddAdditionalFile(string additionalFilePath) - => VisualStudioProject.AddAdditionalFile(additionalFilePath); + => ProjectSystemProject.AddAdditionalFile(additionalFilePath); void IAnalyzerHost.RemoveAdditionalFile(string additionalFilePath) - => VisualStudioProject.RemoveAdditionalFile(additionalFilePath); + => ProjectSystemProject.RemoveAdditionalFile(additionalFilePath); } } diff --git a/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject_IProjectSiteEx.cs b/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject_IProjectSiteEx.cs index 9b2fae18a9f26..901dd26bbe4f8 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject_IProjectSiteEx.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject_IProjectSiteEx.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Runtime.InteropServices; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Workspaces.ProjectSystem; using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.Interop; using Roslyn.Utilities; @@ -14,10 +15,10 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.L { internal abstract partial class AbstractLegacyProject : IProjectSiteEx { - private readonly Stack _batchScopes = new(); + private readonly Stack _batchScopes = new(); public void StartBatch() - => _batchScopes.Push(VisualStudioProject.CreateBatchScope()); + => _batchScopes.Push(ProjectSystemProject.CreateBatchScope()); public void EndBatch() { diff --git a/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject_IVsHierarchyEvents.cs b/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject_IVsHierarchyEvents.cs index bf2bfee67068a..c642cad69efdd 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject_IVsHierarchyEvents.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject_IVsHierarchyEvents.cs @@ -65,12 +65,12 @@ int IVsHierarchyEvents.OnPropertyChanged(uint itemid, int propid, uint flags) if (filePath != null && File.Exists(filePath)) { - VisualStudioProject.FilePath = filePath; + ProjectSystemProject.FilePath = filePath; } if (Hierarchy.TryGetName(out var name)) { - VisualStudioProject.DisplayName = name; + ProjectSystemProject.DisplayName = name; } } diff --git a/src/VisualStudio/Core/Def/ProjectSystem/Legacy/SolutionEventsBatchScopeCreator.cs b/src/VisualStudio/Core/Def/ProjectSystem/Legacy/SolutionEventsBatchScopeCreator.cs index 8a8b4e2408c2f..d20d924255115 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/Legacy/SolutionEventsBatchScopeCreator.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/Legacy/SolutionEventsBatchScopeCreator.cs @@ -10,6 +10,7 @@ using System.Linq; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Workspaces.ProjectSystem; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using Roslyn.Utilities; @@ -24,7 +25,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.L [Export(typeof(SolutionEventsBatchScopeCreator))] internal sealed class SolutionEventsBatchScopeCreator : ForegroundThreadAffinitizedObject { - private readonly List<(VisualStudioProject project, IVsHierarchy hierarchy, VisualStudioProject.BatchScope batchScope)> _fullSolutionLoadScopes = new List<(VisualStudioProject, IVsHierarchy, VisualStudioProject.BatchScope)>(); + private readonly List<(ProjectSystemProject project, IVsHierarchy hierarchy, ProjectSystemProject.BatchScope batchScope)> _fullSolutionLoadScopes = new List<(ProjectSystemProject, IVsHierarchy, ProjectSystemProject.BatchScope)>(); private uint? _runningDocumentTableEventsCookie; @@ -41,7 +42,7 @@ public SolutionEventsBatchScopeCreator(IThreadingContext threadingContext, [Impo _serviceProvider = serviceProvider; } - public void StartTrackingProject(VisualStudioProject project, IVsHierarchy hierarchy) + public void StartTrackingProject(ProjectSystemProject project, IVsHierarchy hierarchy) { AssertIsForeground(); @@ -55,7 +56,7 @@ public void StartTrackingProject(VisualStudioProject project, IVsHierarchy hiera } } - public void StopTrackingProject(VisualStudioProject project) + public void StopTrackingProject(ProjectSystemProject project) { AssertIsForeground(); diff --git a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioProjectCreationInfo.cs b/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioProjectCreationInfo.cs index b1e8c55109347..f88758b30931c 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioProjectCreationInfo.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioProjectCreationInfo.cs @@ -4,17 +4,13 @@ using System; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Workspaces.ProjectSystem; using Microsoft.VisualStudio.Shell.Interop; namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem { - internal sealed class VisualStudioProjectCreationInfo + internal sealed class VisualStudioProjectCreationInfo : ProjectSystemProjectCreationInfo { - public string? AssemblyName { get; set; } - public CompilationOptions? CompilationOptions { get; set; } - public string? FilePath { get; set; } - public ParseOptions? ParseOptions { get; set; } - public IVsHierarchy? Hierarchy { get; set; } public Guid ProjectGuid { get; set; } } diff --git a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioProjectFactory.cs b/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioProjectFactory.cs index 6e48983529a3a..1034e8969eadb 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioProjectFactory.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioProjectFactory.cs @@ -9,11 +9,13 @@ using System.IO; using System.Threading; using System.Threading.Tasks; +using EnvDTE; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Workspaces.ProjectSystem; using Microsoft.VisualStudio.LanguageServices.ExternalAccess.VSTypeScript.Api; using Microsoft.VisualStudio.LanguageServices.Implementation.Diagnostics; using Microsoft.VisualStudio.LanguageServices.Implementation.TaskList; @@ -56,10 +58,10 @@ public VisualStudioProjectFactory( _serviceProvider = (Shell.IAsyncServiceProvider)serviceProvider; } - public Task CreateAndAddToWorkspaceAsync(string projectSystemName, string language, CancellationToken cancellationToken) + public Task CreateAndAddToWorkspaceAsync(string projectSystemName, string language, CancellationToken cancellationToken) => CreateAndAddToWorkspaceAsync(projectSystemName, language, new VisualStudioProjectCreationInfo(), cancellationToken); - public async Task CreateAndAddToWorkspaceAsync( + public async Task CreateAndAddToWorkspaceAsync( string projectSystemName, string language, VisualStudioProjectCreationInfo creationInfo, CancellationToken cancellationToken) { // HACK: Fetch this service to ensure it's still created on the UI thread; once this is @@ -92,66 +94,17 @@ public async Task CreateAndAddToWorkspaceAsync( } // From this point on, we start mutating the solution. So make us non cancellable. +#pragma warning disable IDE0059 // Unnecessary assignment of a value cancellationToken = CancellationToken.None; +#pragma warning restore IDE0059 // Unnecessary assignment of a value - var id = ProjectId.CreateNewId(projectSystemName); - var assemblyName = creationInfo.AssemblyName ?? projectSystemName; - - // We will use the project system name as the default display name of the project - var project = new VisualStudioProject( - _visualStudioWorkspaceImpl, - _dynamicFileInfoProviders, - _hostDiagnosticUpdateSource, - vsixAnalyzerProvider, - id, - displayName: projectSystemName, - language, - assemblyName: assemblyName, - compilationOptions: creationInfo.CompilationOptions, - filePath: creationInfo.FilePath, - parseOptions: creationInfo.ParseOptions); - - var versionStamp = creationInfo.FilePath != null ? VersionStamp.Create(File.GetLastWriteTimeUtc(creationInfo.FilePath)) - : VersionStamp.Create(); - - await _visualStudioWorkspaceImpl.ApplyChangeToWorkspaceAsync(w => - { - _visualStudioWorkspaceImpl.AddProjectToInternalMaps_NoLock(project, creationInfo.Hierarchy, creationInfo.ProjectGuid, projectSystemName); - - var projectInfo = ProjectInfo.Create( - new ProjectInfo.ProjectAttributes( - id, - versionStamp, - name: projectSystemName, - assemblyName: assemblyName, - language: language, - checksumAlgorithm: SourceHashAlgorithms.Default, // will be updated when command line is set - compilationOutputFilePaths: default, // will be updated when command line is set - filePath: creationInfo.FilePath, - telemetryId: creationInfo.ProjectGuid), - compilationOptions: creationInfo.CompilationOptions, - parseOptions: creationInfo.ParseOptions); - - // If we don't have any projects and this is our first project being added, then we'll create a new SolutionId - // and count this as the solution being added so that event is raised. - if (w.CurrentSolution.ProjectIds.Count == 0) - { - var solutionSessionId = GetSolutionSessionId(); - - w.OnSolutionAdded( - SolutionInfo.Create( - SolutionId.CreateNewId(solutionFilePath), - VersionStamp.Create(), - solutionFilePath, - projects: new[] { projectInfo }, - analyzerReferences: w.CurrentSolution.AnalyzerReferences) - .WithTelemetryId(solutionSessionId)); - } - else - { - w.OnProjectAdded(projectInfo); - } - }); + _visualStudioWorkspaceImpl.ProjectSystemProjectFactory.SolutionPath = solutionFilePath; + _visualStudioWorkspaceImpl.ProjectSystemProjectFactory.SolutionTelemetryId = GetSolutionSessionId(); + + var hostInfo = new ProjectSystemHostInfo(_dynamicFileInfoProviders, _hostDiagnosticUpdateSource, vsixAnalyzerProvider); + var project = await _visualStudioWorkspaceImpl.ProjectSystemProjectFactory.CreateAndAddToWorkspaceAsync(projectSystemName, language, creationInfo, hostInfo); + + _visualStudioWorkspaceImpl.AddProjectToInternalMaps(project, creationInfo.Hierarchy, creationInfo.ProjectGuid, projectSystemName); // Ensure that other VS contexts get accurate information that the UIContext for this language is now active. // This is not cancellable as we have already mutated the solution. diff --git a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioProjectOptionsProcessor.cs b/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioProjectOptionsProcessor.cs index 838b2d5a98d22..a4b870eb4c79c 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioProjectOptionsProcessor.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioProjectOptionsProcessor.cs @@ -10,13 +10,14 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Scripting.Hosting; +using Microsoft.CodeAnalysis.Workspaces.ProjectSystem; using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem { internal class VisualStudioProjectOptionsProcessor : IDisposable { - private readonly VisualStudioProject _project; + private readonly ProjectSystemProject _project; private readonly SolutionServices _workspaceServices; private readonly ICommandLineParserService _commandLineParserService; private readonly ITemporaryStorageServiceInternal _temporaryStorageService; @@ -47,7 +48,7 @@ internal class VisualStudioProjectOptionsProcessor : IDisposable private IReferenceCountedDisposable>? _ruleSetFile = null; public VisualStudioProjectOptionsProcessor( - VisualStudioProject project, + ProjectSystemProject project, SolutionServices workspaceServices) { _project = project ?? throw new ArgumentNullException(nameof(project)); diff --git a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioProjectTracker.cs b/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioProjectTracker.cs deleted file mode 100644 index eaeaa45573cbb..0000000000000 --- a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioProjectTracker.cs +++ /dev/null @@ -1,174 +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.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using System.Threading; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Editor.Shared.Utilities; -using Microsoft.CodeAnalysis.Host; - -namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem -{ -#pragma warning disable IDE0060 // Remove unused parameter - compatibility shim for TypeScript - - [Obsolete("This is a compatibility shim for TypeScript; please do not use it.")] - internal sealed partial class VisualStudioProjectTracker - { - private readonly Workspace _workspace; - private readonly VisualStudioProjectFactory _projectFactory; - internal IThreadingContext ThreadingContext { get; } - - internal HostWorkspaceServices WorkspaceServices => _workspace.Services; - - [Obsolete("This is a compatibility shim for TypeScript; please do not use it.")] - private readonly Dictionary _projects = new(); - - [Obsolete("This is a compatibility shim; please do not use it.")] - public VisualStudioProjectTracker(Workspace workspace, VisualStudioProjectFactory projectFactory, IThreadingContext threadingContext) - { - _workspace = workspace; - _projectFactory = projectFactory; - ThreadingContext = threadingContext; - DocumentProvider = new DocumentProvider(); - } - - [Obsolete("This is a compatibility shim for TypeScript; please do not use it.")] - public DocumentProvider DocumentProvider { get; set; } - - public Workspace Workspace => _workspace; - - /* - - private void FinishLoad() - { - // Check that the set of analyzers is complete and consistent. - GetAnalyzerDependencyCheckingService()?.ReanalyzeSolutionForConflicts(); - } - - private AnalyzerDependencyCheckingService GetAnalyzerDependencyCheckingService() - { - var componentModel = (IComponentModel)_serviceProvider.GetService(typeof(SComponentModel)); - - return componentModel.GetService(); - } - - */ - - public ProjectId GetOrCreateProjectIdForPath(string filePath, string projectDisplayName) - { - // HACK: to keep F# working, we will ensure we return the ProjectId if there is a project that matches this path. Otherwise, we'll just return - // a random ProjectId, which is sufficient for their needs. They'll simply observe there is no project with that ID, and then go and create a - // new project. Then they call this function again, and fetch the real ID. - return _workspace.CurrentSolution.Projects.FirstOrDefault(p => p.FilePath == filePath)?.Id ?? ProjectId.CreateNewId("ProjectNotFound"); - } - - [Obsolete("This is a compatibility shim for TypeScript and F#; please do not use it.")] - public AbstractProject GetProject(ProjectId projectId) - { - // HACK: if we have a TypeScript project, they expect to return the real thing deriving from AbstractProject - if (_projects.TryGetValue(projectId, out var typeScriptProject)) - { - return typeScriptProject; - } - - // HACK: to keep F# working, we will ensure that if there is a project with that ID, we will return a non-null value, otherwise we'll return null. - // It doesn't actually matter *what* the project is, so we'll just return something silly - var project = _workspace.CurrentSolution.GetProject(projectId); - - if (project != null) - { - return new StubProject(this, project); - } - else - { - return null; - } - } - - [Obsolete("This is a compatibility shim for TypeScript and F#; please do not use it.")] - internal bool TryGetProjectByBinPath(string filePath, out AbstractProject project) - { - var projectsWithBinPath = _workspace.CurrentSolution.Projects.Where(p => string.Equals(p.OutputFilePath, filePath, StringComparison.OrdinalIgnoreCase)).ToList(); - - if (projectsWithBinPath.Count == 1) - { - project = new StubProject(this, projectsWithBinPath[0]); - return true; - } - else - { - project = null; - return false; - } - } - - [Obsolete("This is a compatibility shim for TypeScript and F#; please do not use it.")] - private sealed class StubProject : AbstractProject - { - private readonly ProjectId _id; - - public StubProject(VisualStudioProjectTracker projectTracker, Project project) - : base(projectTracker, null, project.Name + "_Stub", project.FilePath, null, project.Language, Guid.Empty, null, null, null, null) - { - _id = project.Id; - } - - public override ProjectId Id => _id; - } - - [Obsolete("This is a compatibility shim for TypeScript; please do not use it.")] - public void AddProject(AbstractProject project) - { - if (_projectFactory != null) - { - var creationInfo = new VisualStudioProjectCreationInfo - { - AssemblyName = project.AssemblyName, - FilePath = project.ProjectFilePath, - Hierarchy = project.Hierarchy, - ProjectGuid = project.Guid, - }; - project.VisualStudioProject = this.ThreadingContext.JoinableTaskFactory.Run(() => _projectFactory.CreateAndAddToWorkspaceAsync( - project.ProjectSystemName, project.Language, creationInfo, CancellationToken.None)); - project.UpdateVisualStudioProjectProperties(); - } - else - { - // We don't have an ID, so make something up - project.ExplicitId = ProjectId.CreateNewId(project.ProjectSystemName); - Workspace.OnProjectAdded(ProjectInfo.Create(project.ExplicitId, VersionStamp.Create(), project.ProjectSystemName, project.ProjectSystemName, project.Language)); - } - - _projects[project.Id] = project; - } - - [Obsolete("This is a compatibility shim for TypeScript; please do not use it.")] - public bool ContainsProject(AbstractProject project) - { - // This will be set as long as the project has been added and not since removed - return _projects.Values.Contains(project); - } - - [Obsolete("This is a compatibility shim for TypeScript; please do not use it.")] - public void RemoveProject(AbstractProject project) - { - _projects.Remove(project.Id); - - if (project.ExplicitId != null) - { - Workspace.OnProjectRemoved(project.ExplicitId); - } - else - { - project.VisualStudioProject.RemoveFromWorkspace(); - project.VisualStudioProject = null; - } - } - } -} diff --git a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspaceImpl.OpenFileTracker.cs b/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspaceImpl.OpenFileTracker.cs index 1287b2ed072c6..753feab9e38ec 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspaceImpl.OpenFileTracker.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspaceImpl.OpenFileTracker.cs @@ -15,6 +15,7 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Workspaces.ProjectSystem; using Microsoft.VisualStudio.ComponentModelHost; using Microsoft.VisualStudio.Editor; using Microsoft.VisualStudio.Shell; @@ -37,6 +38,7 @@ public sealed class OpenFileTracker : IRunningDocumentTableEventListener private readonly ForegroundThreadAffinitizedObject _foregroundAffinitization; private readonly VisualStudioWorkspaceImpl _workspace; + private readonly ProjectSystemProjectFactory _projectSystemProjectFactory; private readonly IAsynchronousOperationListener _asyncOperationListener; private readonly RunningDocumentTableEventTracker _runningDocumentTableEventTracker; @@ -97,9 +99,10 @@ private readonly MultiDictionary private const int CutoffForCheckingAllRunningDocumentTableDocuments = 10; - private OpenFileTracker(VisualStudioWorkspaceImpl workspace, IVsRunningDocumentTable runningDocumentTable, IComponentModel componentModel) + private OpenFileTracker(VisualStudioWorkspaceImpl workspace, ProjectSystemProjectFactory projectSystemProjectFactory, IVsRunningDocumentTable runningDocumentTable, IComponentModel componentModel) { _workspace = workspace; + _projectSystemProjectFactory = projectSystemProjectFactory; _foregroundAffinitization = new ForegroundThreadAffinitizedObject(workspace._threadingContext, assertIsForeground: true); _asyncOperationListener = componentModel.GetService().GetListener(FeatureAttribute.Workspace); _runningDocumentTableEventTracker = new RunningDocumentTableEventTracker(workspace._threadingContext, @@ -123,7 +126,7 @@ void IRunningDocumentTableEventListener.OnRenameDocument(string newMoniker, stri { } - public static async Task CreateAsync(VisualStudioWorkspaceImpl workspace, IAsyncServiceProvider asyncServiceProvider) + public static async Task CreateAsync(VisualStudioWorkspaceImpl workspace, ProjectSystemProjectFactory projectSystemProjectFactory, IAsyncServiceProvider asyncServiceProvider) { var runningDocumentTable = (IVsRunningDocumentTable?)await asyncServiceProvider.GetServiceAsync(typeof(SVsRunningDocumentTable)).ConfigureAwait(true); Assumes.Present(runningDocumentTable); @@ -131,16 +134,16 @@ public static async Task CreateAsync(VisualStudioWorkspaceImpl var componentModel = (IComponentModel?)await asyncServiceProvider.GetServiceAsync(typeof(SComponentModel)).ConfigureAwait(true); Assumes.Present(componentModel); - return new OpenFileTracker(workspace, runningDocumentTable, componentModel); + return new OpenFileTracker(workspace, projectSystemProjectFactory, runningDocumentTable, componentModel); } private void TryOpeningDocumentsForMoniker(string moniker, ITextBuffer textBuffer, IVsHierarchy? hierarchy) { _foregroundAffinitization.AssertIsForeground(); - _workspace.ApplyChangeToWorkspace(w => + _projectSystemProjectFactory.ApplyChangeToWorkspace(w => { - var documentIds = _workspace.CurrentSolution.GetDocumentIdsWithFilePath(moniker); + var documentIds = _projectSystemProjectFactory.Workspace.CurrentSolution.GetDocumentIdsWithFilePath(moniker); if (documentIds.IsDefaultOrEmpty) { return; @@ -166,7 +169,7 @@ private void TryOpeningDocumentsForMoniker(string moniker, ITextBuffer textBuffe foreach (var documentId in documentIds) { - if (!w.IsDocumentOpen(documentId) && !_workspace._documentsNotFromFiles.Contains(documentId)) + if (!w.IsDocumentOpen(documentId) && !_projectSystemProjectFactory.DocumentsNotFromFiles.Contains(documentId)) { var isCurrentContext = documentId.ProjectId == activeContextProjectId; if (w.CurrentSolution.ContainsDocument(documentId)) @@ -284,7 +287,7 @@ private void RefreshContextForMoniker(string moniker, IVsHierarchy hierarchy) { _foregroundAffinitization.AssertIsForeground(); - _workspace.ApplyChangeToWorkspace(w => + _projectSystemProjectFactory.ApplyChangeToWorkspace(w => { var documentIds = _workspace.CurrentSolution.GetDocumentIdsWithFilePath(moniker); if (documentIds.IsDefaultOrEmpty || documentIds.Length == 1) @@ -326,7 +329,7 @@ private void TryClosingDocumentsForMoniker(string moniker) UnsubscribeFromWatchedHierarchies(moniker); - _workspace.ApplyChangeToWorkspace(w => + _projectSystemProjectFactory.ApplyChangeToWorkspace(w => { var documentIds = w.CurrentSolution.GetDocumentIdsWithFilePath(moniker); if (documentIds.IsDefaultOrEmpty) @@ -336,7 +339,7 @@ private void TryClosingDocumentsForMoniker(string moniker) foreach (var documentId in documentIds) { - if (w.IsDocumentOpen(documentId) && !_workspace._documentsNotFromFiles.Contains(documentId)) + if (w.IsDocumentOpen(documentId) && !_projectSystemProjectFactory.DocumentsNotFromFiles.Contains(documentId)) { var solution = w.CurrentSolution; diff --git a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspaceImpl.SolutionAnalyzerSetterService.cs b/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspaceImpl.SolutionAnalyzerSetterService.cs index 51945225467d8..88327564f95a9 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspaceImpl.SolutionAnalyzerSetterService.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspaceImpl.SolutionAnalyzerSetterService.cs @@ -35,7 +35,7 @@ public SolutionAnalyzerSetter(VisualStudioWorkspaceImpl workspace) => _workspace = workspace; public void SetAnalyzerReferences(ImmutableArray references) - => _workspace.ApplyChangeToWorkspace(w => w.SetCurrentSolution(s => s.WithAnalyzerReferences(references), WorkspaceChangeKind.SolutionChanged)); + => _workspace.ProjectSystemProjectFactory.ApplyChangeToWorkspace(w => w.SetCurrentSolution(s => s.WithAnalyzerReferences(references), WorkspaceChangeKind.SolutionChanged)); } } } diff --git a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspaceImpl.cs b/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspaceImpl.cs index eeb532930a7db..62c0e687b27bd 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspaceImpl.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspaceImpl.cs @@ -51,6 +51,7 @@ using Solution = Microsoft.CodeAnalysis.Solution; using Microsoft.CodeAnalysis.Notification; using Microsoft.CodeAnalysis.ProjectSystem; +using Microsoft.CodeAnalysis.Workspaces.ProjectSystem; namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem { @@ -67,17 +68,11 @@ internal abstract partial class VisualStudioWorkspaceImpl : VisualStudioWorkspac private readonly IProjectionBufferFactoryService _projectionBufferFactoryService; private readonly IGlobalOptionService _globalOptions; - [Obsolete("This is a compatibility shim for TypeScript; please do not use it.")] - private readonly Lazy _projectFactory; - private readonly ITextBufferCloneService _textBufferCloneService; /// - /// The main gate to synchronize updates to this solution. + /// Guards any updates to the maps here that aren't updated via interlocked updates. /// - /// - /// See the Readme.md in this directory for further comments about threading in this area. - /// private readonly SemaphoreSlim _gate = new SemaphoreSlim(initialCount: 1); /// @@ -88,12 +83,6 @@ internal abstract partial class VisualStudioWorkspaceImpl : VisualStudioWorkspac private ImmutableDictionary _projectToHierarchyMap = ImmutableDictionary.Empty; private ImmutableDictionary _projectToGuidMap = ImmutableDictionary.Empty; - /// Should be updated with . - private ImmutableDictionary _projectToMaxSupportedLangVersionMap = ImmutableDictionary.Empty; - - /// Should be updated with . - private ImmutableDictionary _projectToDependencyNodeTargetIdentifier = ImmutableDictionary.Empty; - /// /// A map to fetch the path to a rule set file for a project. This right now is only used to implement /// and any other use is extremely suspicious, since direct use of this is out of @@ -102,32 +91,19 @@ internal abstract partial class VisualStudioWorkspaceImpl : VisualStudioWorkspac /// Should be updated with . private ImmutableDictionary> _projectToRuleSetFilePath = ImmutableDictionary>.Empty; - private readonly Dictionary> _projectSystemNameToProjectsMap = new(); + private readonly Dictionary> _projectSystemNameToProjectsMap = new(); /// /// Only safe to use on the UI thread. /// private readonly Dictionary _languageToProjectExistsUIContext = new(); - /// - /// A set of documents that were added by , and aren't otherwise - /// tracked for opening/closing. - /// - private ImmutableHashSet _documentsNotFromFiles = ImmutableHashSet.Empty; - - /// - /// Indicates whether the current solution is closing. - /// - private bool _solutionClosing; - - [Obsolete("This is a compatibility shim for TypeScript; please do not use it.")] - internal VisualStudioProjectTracker? _projectTracker; - private VirtualMemoryNotificationListener? _memoryListener; private OpenFileTracker? _openFileTracker; internal IFileChangeWatcher FileChangeWatcher { get; } - internal FileWatchedPortableExecutableReferenceFactory FileWatchedReferenceFactory { get; } + + internal ProjectSystemProjectFactory ProjectSystemProjectFactory { get; } private readonly Lazy _projectCodeModelFactory; @@ -145,23 +121,16 @@ public VisualStudioWorkspaceImpl(ExportProvider exportProvider, IAsyncServicePro _projectionBufferFactoryService = exportProvider.GetExportedValue(); _projectCodeModelFactory = exportProvider.GetExport(); - // We fetch this lazily because VisualStudioProjectFactory depends on VisualStudioWorkspaceImpl -- we have a circularity. Since this - // exists right now as a compat shim, we'll just do this. -#pragma warning disable CS0618 // Type or member is obsolete - _projectFactory = exportProvider.GetExport(); -#pragma warning restore CS0618 // Type or member is obsolete - _foregroundObject = new ForegroundThreadAffinitizedObject(_threadingContext); _textBufferFactoryService.TextBufferCreated += AddTextBufferCloneServiceToBuffer; _projectionBufferFactoryService.ProjectionBufferCreated += AddTextBufferCloneServiceToBuffer; - _ = Task.Run(() => InitializeUIAffinitizedServicesAsync(asyncServiceProvider)); - FileChangeWatcher = exportProvider.GetExportedValue().Watcher; - FileWatchedReferenceFactory = new FileWatchedPortableExecutableReferenceFactory(this.Services.SolutionServices, FileChangeWatcher); - FileWatchedReferenceFactory.ReferenceChanged += this.StartRefreshingMetadataReferencesForFile; + ProjectSystemProjectFactory = new ProjectSystemProjectFactory(this, FileChangeWatcher, QueueCheckForFilesBeingOpen, RemoveProjectFromMaps); + + _ = Task.Run(() => InitializeUIAffinitizedServicesAsync(asyncServiceProvider)); _lazyExternalErrorDiagnosticUpdateSource = new Lazy(() => new ExternalErrorDiagnosticUpdateSource( @@ -229,9 +198,9 @@ public async Task InitializeUIAffinitizedServicesAsync(IAsyncServiceProvider asy var telemetrySession = TelemetryService.DefaultSession; var solutionClosingContext = UIContext.FromUIContextGuid(VSConstants.UICONTEXT.SolutionClosing_guid); - solutionClosingContext.UIContextChanged += (_, e) => _solutionClosing = e.Activated; + solutionClosingContext.UIContextChanged += (_, e) => ProjectSystemProjectFactory.SolutionClosing = e.Activated; - var openFileTracker = await OpenFileTracker.CreateAsync(this, asyncServiceProvider).ConfigureAwait(true); + var openFileTracker = await OpenFileTracker.CreateAsync(this, ProjectSystemProjectFactory, asyncServiceProvider).ConfigureAwait(true); var memoryListener = await VirtualMemoryNotificationListener.CreateAsync(this, _threadingContext, asyncServiceProvider, _globalOptions, _threadingContext.DisposalToken).ConfigureAwait(true); // Update our fields first, so any asynchronous work that needs to use these is able to see the service. @@ -264,51 +233,22 @@ public void QueueCheckForFilesBeingOpen(ImmutableArray newFileNames) public void ProcessQueuedWorkOnUIThread() => _openFileTracker?.ProcessQueuedWorkOnUIThread(); - internal void AddProjectToInternalMaps_NoLock(VisualStudioProject project, IVsHierarchy? hierarchy, Guid guid, string projectSystemName) + internal void AddProjectToInternalMaps(ProjectSystemProject project, IVsHierarchy? hierarchy, Guid guid, string projectSystemName) { - Contract.ThrowIfFalse(_gate.CurrentCount == 0); - - _projectToHierarchyMap = _projectToHierarchyMap.Add(project.Id, hierarchy); - _projectToGuidMap = _projectToGuidMap.Add(project.Id, guid); - _projectSystemNameToProjectsMap.MultiAdd(projectSystemName, project); + using (_gate.DisposableWait()) + { + _projectToHierarchyMap = _projectToHierarchyMap.Add(project.Id, hierarchy); + _projectToGuidMap = _projectToGuidMap.Add(project.Id, guid); + _projectSystemNameToProjectsMap.MultiAdd(projectSystemName, project); + } } - internal void AddProjectRuleSetFileToInternalMaps(VisualStudioProject project, Func ruleSetFilePathFunc) + internal void AddProjectRuleSetFileToInternalMaps(ProjectSystemProject project, Func ruleSetFilePathFunc) { Contract.ThrowIfFalse(ImmutableInterlocked.TryAdd(ref _projectToRuleSetFilePath, project.Id, ruleSetFilePathFunc)); } - internal void AddDocumentToDocumentsNotFromFiles_NoLock(DocumentId documentId) - { - Contract.ThrowIfFalse(_gate.CurrentCount == 0); - - _documentsNotFromFiles = _documentsNotFromFiles.Add(documentId); - } - - internal void RemoveDocumentToDocumentsNotFromFiles_NoLock(DocumentId documentId) - { - Contract.ThrowIfFalse(_gate.CurrentCount == 0); - _documentsNotFromFiles = _documentsNotFromFiles.Remove(documentId); - } - - [Obsolete("This is a compatibility shim for TypeScript; please do not use it.")] - internal VisualStudioProjectTracker GetProjectTrackerAndInitializeIfNecessary() - { - _projectTracker ??= new VisualStudioProjectTracker(this, _projectFactory.Value, _threadingContext); - - return _projectTracker; - } - - [Obsolete("This is a compatibility shim for TypeScript and F#; please do not use it.")] - internal VisualStudioProjectTracker ProjectTracker - { - get - { - return GetProjectTrackerAndInitializeIfNecessary(); - } - } - - internal VisualStudioProject? GetProjectWithHierarchyAndName(IVsHierarchy hierarchy, string projectName) + internal ProjectSystemProject? GetProjectWithHierarchyAndName(IVsHierarchy hierarchy, string projectName) { using (_gate.DisposableWait()) { @@ -316,7 +256,7 @@ internal VisualStudioProjectTracker ProjectTracker } } - private VisualStudioProject? GetProjectWithHierarchyAndName_NoLock(IVsHierarchy hierarchy, string projectName) + private ProjectSystemProject? GetProjectWithHierarchyAndName_NoLock(IVsHierarchy hierarchy, string projectName) { if (_projectSystemNameToProjectsMap.TryGetValue(projectName, out var projects)) { @@ -350,14 +290,6 @@ internal VisualStudioProjectTracker ProjectTracker } } - [Obsolete("This is a compatibility shim for TypeScript; please do not use it.")] - internal IVisualStudioHostDocument? GetHostDocument(DocumentId documentId) - { - // TypeScript only calls this to immediately check if the document is a ContainedDocument. Because of that we can just check for - // ContainedDocuments - return ContainedDocument.TryGetContainedDocument(documentId); - } - public override EnvDTE.FileCodeModel GetFileCodeModel(DocumentId documentId) { if (documentId == null) @@ -469,7 +401,7 @@ public override bool CanApplyCompilationOptionChange(CompilationOptions oldOptio public override bool CanApplyParseOptionChange(ParseOptions oldOptions, ParseOptions newOptions, CodeAnalysis.Project project) { - _projectToMaxSupportedLangVersionMap.TryGetValue(project.Id, out var maxSupportLangVersion); + var maxSupportLangVersion = ProjectSystemProjectFactory.TryGetMaxSupportedLanguageVersion(project.Id); return project.Services.GetRequiredService().CanApplyChange(oldOptions, newOptions, maxSupportLangVersion); } @@ -1349,9 +1281,7 @@ internal override Guid GetProjectGuid(ProjectId projectId) internal string? TryGetDependencyNodeTargetIdentifier(ProjectId projectId) { - // This doesn't take a lock since _projectToDependencyNodeTargetIdentifier is immutable - _projectToDependencyNodeTargetIdentifier.TryGetValue(projectId, out var identifier); - return identifier; + return ProjectSystemProjectFactory.TryGetDependencyNodeTargetIdentifier(projectId); } internal override void SetDocumentContext(DocumentId documentId) @@ -1438,7 +1368,6 @@ protected override void Dispose(bool finalize) { _textBufferFactoryService.TextBufferCreated -= AddTextBufferCloneServiceToBuffer; _projectionBufferFactoryService.ProjectionBufferCreated -= AddTextBufferCloneServiceToBuffer; - FileWatchedReferenceFactory.ReferenceChanged -= StartRefreshingMetadataReferencesForFile; if (_lazyExternalErrorDiagnosticUpdateSource.IsValueCreated) { @@ -1553,147 +1482,11 @@ internal override bool CanAddProjectReference(ProjectId referencingProject, Proj return result != (uint)__VSREFERENCEQUERYRESULT.REFERENCE_DENY; } - /// - /// Applies a single operation to the workspace. should be a call to one of the protected Workspace.On* methods. - /// - public void ApplyChangeToWorkspace(Action action) - { - using (_gate.DisposableWait()) - { - action(this); - } - } - - /// - /// Applies a single operation to the workspace. should be a call to one of the protected Workspace.On* methods. - /// - public async ValueTask ApplyChangeToWorkspaceAsync(Action action) - { - using (await _gate.DisposableWaitAsync().ConfigureAwait(false)) - { - action(this); - } - } - - /// - /// Applies a single operation to the workspace. should be a call to one of the protected Workspace.On* methods. - /// - public async ValueTask ApplyChangeToWorkspaceMaybeAsync(bool useAsync, Action action) - { - using (useAsync ? await _gate.DisposableWaitAsync().ConfigureAwait(false) : _gate.DisposableWait()) - { - action(this); - } - } - - /// - /// Applies a solution transformation to the workspace and triggers workspace changed event for specified . - /// The transformation shall only update the project of the solution with the specified . - /// - public void ApplyChangeToWorkspace(ProjectId projectId, Func solutionTransformation) + internal void RemoveProjectFromMaps(CodeAnalysis.Project project) { - using (_gate.DisposableWait()) - { - SetCurrentSolution(solutionTransformation, WorkspaceChangeKind.ProjectChanged, projectId); - } - } - - /// - public void ApplyBatchChangeToWorkspace(Action mutation) - { - ApplyBatchChangeToWorkspaceMaybeAsync(useAsync: false, mutation).VerifyCompleted(); - } - - /// - public Task ApplyBatchChangeToWorkspaceAsync(Action mutation) - { - return ApplyBatchChangeToWorkspaceMaybeAsync(useAsync: true, mutation); - } - - /// - /// Applies a change to the workspace that can do any number of project changes. - /// - /// This is needed to synchronize with to avoid any races. This - /// method could be moved down to the core Workspace layer and then could use the synchronization lock there. - public async Task ApplyBatchChangeToWorkspaceMaybeAsync(bool useAsync, Action mutation) - { - using (useAsync ? await _gate.DisposableWaitAsync().ConfigureAwait(false) : _gate.DisposableWait()) - { - var solutionChanges = new SolutionChangeAccumulator(CurrentSolution); - mutation(solutionChanges); - - ApplyBatchChangeToWorkspace_NoLock(solutionChanges); - } - } - - private void ApplyBatchChangeToWorkspace_NoLock(SolutionChangeAccumulator solutionChanges) - { - Contract.ThrowIfFalse(_gate.CurrentCount == 0); - - if (!solutionChanges.HasChange) - return; - - this.SetCurrentSolution( - _ => solutionChanges.Solution, - solutionChanges.WorkspaceChangeKind, - solutionChanges.WorkspaceChangeProjectId, - solutionChanges.WorkspaceChangeDocumentId, - onBeforeUpdate: (_, _) => - { - // Clear out mutable state not associated with the solution snapshot (for example, which documents are - // currently open). - foreach (var documentId in solutionChanges.DocumentIdsRemoved) - this.ClearDocumentData(documentId); - }); - } - - private readonly Dictionary _projectReferenceInfoMap = new(); - - private ProjectReferenceInformation GetReferenceInfo_NoLock(ProjectId projectId) - { - Contract.ThrowIfFalse(_gate.CurrentCount == 0); - - return _projectReferenceInfoMap.GetOrAdd(projectId, _ => new ProjectReferenceInformation()); - } - - /// - /// Removes the project from the various maps this type maintains; it's still up to the caller to actually remove - /// the project in one way or another. - /// - internal void RemoveProjectFromTrackingMaps_NoLock(ProjectId projectId) - { - string? languageName; - - Contract.ThrowIfFalse(_gate.CurrentCount == 0); - - languageName = CurrentSolution.GetRequiredProject(projectId).Language; - - if (_projectReferenceInfoMap.TryGetValue(projectId, out var projectReferenceInfo)) - { - // If we still had any output paths, we'll want to remove them to cause conversion back to metadata references. - // The call below implicitly is modifying the collection we've fetched, so we'll make a copy. - var solutionChanges = new SolutionChangeAccumulator(this.CurrentSolution); - - foreach (var outputPath in projectReferenceInfo.OutputPaths.ToList()) - { - RemoveProjectOutputPath_NoLock(solutionChanges, projectId, outputPath); - } - - ApplyBatchChangeToWorkspace_NoLock(solutionChanges); - - _projectReferenceInfoMap.Remove(projectId); - } - - _projectToHierarchyMap = _projectToHierarchyMap.Remove(projectId); - _projectToGuidMap = _projectToGuidMap.Remove(projectId); - - ImmutableInterlocked.TryRemove(ref _projectToMaxSupportedLangVersionMap, projectId, out _); - ImmutableInterlocked.TryRemove(ref _projectToDependencyNodeTargetIdentifier, projectId, out _); - ImmutableInterlocked.TryRemove(ref _projectToRuleSetFilePath, projectId, out _); - foreach (var (projectName, projects) in _projectSystemNameToProjectsMap) { - if (projects.RemoveAll(p => p.Id == projectId) > 0) + if (projects.RemoveAll(p => p.Id == project.Id) > 0) { if (projects.Count == 0) { @@ -1704,372 +1497,19 @@ internal void RemoveProjectFromTrackingMaps_NoLock(ProjectId projectId) } } - // Try to update the UI context info. But cancel that work if we're shutting down. - _threadingContext.RunWithShutdownBlockAsync(async cancellationToken => - { - using var asyncToken = _workspaceListener.BeginAsyncOperation(nameof(RefreshProjectExistsUIContextForLanguageAsync)); - await RefreshProjectExistsUIContextForLanguageAsync(languageName, cancellationToken).ConfigureAwait(false); - }); - } - - internal void RemoveSolution_NoLock() - { - Contract.ThrowIfFalse(_gate.CurrentCount == 0); - - // At this point, we should have had RemoveProjectFromTrackingMaps_NoLock called for everything else, so it's just the solution itself - // to clean up - Contract.ThrowIfFalse(_projectReferenceInfoMap.Count == 0); - Contract.ThrowIfFalse(_projectToHierarchyMap.Count == 0); - Contract.ThrowIfFalse(_projectToGuidMap.Count == 0); - Contract.ThrowIfFalse(_projectToMaxSupportedLangVersionMap.Count == 0); - Contract.ThrowIfFalse(_projectToDependencyNodeTargetIdentifier.Count == 0); - Contract.ThrowIfFalse(_projectToRuleSetFilePath.Count == 0); - Contract.ThrowIfFalse(_projectSystemNameToProjectsMap.Count == 0); - - // Create a new empty solution and set this; we will reuse the same SolutionId and path since components still may have persistence information they still need - // to look up by that location; we also keep the existing analyzer references around since those are host-level analyzers that were loaded asynchronously. - ClearOpenDocuments(); - - SetCurrentSolution( - solution => CreateSolution( - SolutionInfo.Create( - SolutionId.CreateNewId(), - VersionStamp.Create(), - analyzerReferences: solution.AnalyzerReferences)), - WorkspaceChangeKind.SolutionRemoved); - } - - private sealed class ProjectReferenceInformation - { - public readonly List OutputPaths = new(); - public readonly List<(string path, ProjectReference projectReference)> ConvertedProjectReferences = new List<(string path, ProjectReference)>(); - } - - /// - /// A multimap from an output path to the project outputting to it. Ideally, this shouldn't ever - /// actually be a true multimap, since we shouldn't have two projects outputting to the same path, but - /// any bug by a project adding the wrong output path means we could end up with some duplication. - /// In that case, we'll temporarily have two until (hopefully) somebody removes it. - /// - private readonly Dictionary> _projectsByOutputPath = new(StringComparer.OrdinalIgnoreCase); - - public void AddProjectOutputPath_NoLock(SolutionChangeAccumulator solutionChanges, ProjectId projectId, string outputPath) - { - Contract.ThrowIfFalse(_gate.CurrentCount == 0); - - var projectReferenceInformation = GetReferenceInfo_NoLock(projectId); - - projectReferenceInformation.OutputPaths.Add(outputPath); - _projectsByOutputPath.MultiAdd(outputPath, projectId); + _projectToHierarchyMap = _projectToHierarchyMap.Remove(project.Id); + _projectToGuidMap = _projectToGuidMap.Remove(project.Id); - var projectsForOutputPath = _projectsByOutputPath[outputPath]; - var distinctProjectsForOutputPath = projectsForOutputPath.Distinct().ToList(); + ImmutableInterlocked.TryRemove(ref _projectToRuleSetFilePath, project.Id, out _); - // If we have exactly one, then we're definitely good to convert - if (projectsForOutputPath.Count == 1) - { - ConvertMetadataReferencesToProjectReferences_NoLock(solutionChanges, projectId, outputPath); - } - else if (distinctProjectsForOutputPath.Count == 1) - { - // The same project has multiple output paths that are the same. Any project would have already been converted - // by the prior add, so nothing further to do - } - else - { - // We have more than one project outputting to the same path. This shouldn't happen but we'll convert back - // because now we don't know which project to reference. - foreach (var otherProjectId in projectsForOutputPath) - { - // We know that since we're adding a path to projectId and we're here that we couldn't have already - // had a converted reference to us, instead we need to convert things that are pointing to the project - // we're colliding with - if (otherProjectId != projectId) - { - ConvertProjectReferencesToMetadataReferences_NoLock(solutionChanges, otherProjectId, outputPath); - } - } - } - } - - /// - /// Attempts to convert all metadata references to to a project reference to . - /// - /// The of the project that could be referenced in place of the output path. - /// The output path to replace. - [PerformanceSensitive("https://github.com/dotnet/roslyn/issues/31306", - Constraint = "Avoid calling " + nameof(CodeAnalysis.Solution.GetProject) + " to avoid realizing all projects.")] - private void ConvertMetadataReferencesToProjectReferences_NoLock(SolutionChangeAccumulator solutionChanges, ProjectId projectIdToReference, string outputPath) - { - Contract.ThrowIfFalse(_gate.CurrentCount == 0); - - foreach (var projectIdToRetarget in solutionChanges.Solution.ProjectIds) - { - if (CanConvertMetadataReferenceToProjectReference(solutionChanges.Solution, projectIdToRetarget, referencedProjectId: projectIdToReference)) - { - // PERF: call GetProjectState instead of GetProject, otherwise creating a new project might force all - // Project instances to get created. - foreach (PortableExecutableReference reference in solutionChanges.Solution.GetProjectState(projectIdToRetarget)!.MetadataReferences) - { - if (string.Equals(reference.FilePath, outputPath, StringComparison.OrdinalIgnoreCase)) - { - FileWatchedReferenceFactory.StopWatchingReference(reference); - - var projectReference = new ProjectReference(projectIdToReference, reference.Properties.Aliases, reference.Properties.EmbedInteropTypes); - var newSolution = solutionChanges.Solution.RemoveMetadataReference(projectIdToRetarget, reference) - .AddProjectReference(projectIdToRetarget, projectReference); - - solutionChanges.UpdateSolutionForProjectAction(projectIdToRetarget, newSolution); - - GetReferenceInfo_NoLock(projectIdToRetarget).ConvertedProjectReferences.Add( - (reference.FilePath!, projectReference)); - - // We have converted one, but you could have more than one reference with different aliases - // that we need to convert, so we'll keep going - } - } - } - } - } - - [PerformanceSensitive("https://github.com/dotnet/roslyn/issues/31306", - Constraint = "Avoid calling " + nameof(CodeAnalysis.Solution.GetProject) + " to avoid realizing all projects.")] - private static bool CanConvertMetadataReferenceToProjectReference(Solution solution, ProjectId projectIdWithMetadataReference, ProjectId referencedProjectId) - { - // We can never make a project reference ourselves. This isn't a meaningful scenario, but if somebody does this by accident - // we do want to throw exceptions. - if (projectIdWithMetadataReference == referencedProjectId) - { - return false; - } - - // PERF: call GetProjectState instead of GetProject, otherwise creating a new project might force all - // Project instances to get created. - var projectWithMetadataReference = solution.GetProjectState(projectIdWithMetadataReference); - var referencedProject = solution.GetProjectState(referencedProjectId); - - Contract.ThrowIfNull(projectWithMetadataReference); - Contract.ThrowIfNull(referencedProject); - - // We don't want to convert a metadata reference to a project reference if the project being referenced isn't something - // we can create a Compilation for. For example, if we have a C# project, and it's referencing a F# project via a metadata reference - // everything would be fine if we left it a metadata reference. Converting it to a project reference means we couldn't create a Compilation - // anymore in the IDE, since the C# compilation would need to reference an F# compilation. F# projects referencing other F# projects though - // do expect this to work, and so we'll always allow references through of the same language. - if (projectWithMetadataReference.Language != referencedProject.Language) - { - if (projectWithMetadataReference.LanguageServices.GetService() != null && - referencedProject.LanguageServices.GetService() == null) - { - // We're referencing something that we can't create a compilation from something that can, so keep the metadata reference - return false; - } - } - - // If this is going to cause a circular reference, also disallow it - if (solution.GetProjectDependencyGraph().GetProjectsThatThisProjectTransitivelyDependsOn(referencedProjectId).Contains(projectIdWithMetadataReference)) - { - return false; - } - - return true; - } - - /// - /// Finds all projects that had a project reference to and convert it back to a metadata reference. - /// - /// The of the project being referenced. - /// The output path of the given project to remove the link to. - [PerformanceSensitive( - "https://github.com/dotnet/roslyn/issues/37616", - Constraint = "Update ConvertedProjectReferences in place to avoid duplicate list allocations.")] - private void ConvertProjectReferencesToMetadataReferences_NoLock(SolutionChangeAccumulator solutionChanges, ProjectId projectId, string outputPath) - { - Contract.ThrowIfFalse(_gate.CurrentCount == 0); - - foreach (var projectIdToRetarget in solutionChanges.Solution.ProjectIds) - { - var referenceInfo = GetReferenceInfo_NoLock(projectIdToRetarget); - - // Update ConvertedProjectReferences in place to avoid duplicate list allocations - for (var i = 0; i < referenceInfo.ConvertedProjectReferences.Count; i++) - { - var convertedReference = referenceInfo.ConvertedProjectReferences[i]; - - if (string.Equals(convertedReference.path, outputPath, StringComparison.OrdinalIgnoreCase) && - convertedReference.projectReference.ProjectId == projectId) - { - var metadataReference = - FileWatchedReferenceFactory.CreateReferenceAndStartWatchingFile( - convertedReference.path, - new MetadataReferenceProperties( - aliases: convertedReference.projectReference.Aliases, - embedInteropTypes: convertedReference.projectReference.EmbedInteropTypes)); - - var newSolution = solutionChanges.Solution.RemoveProjectReference(projectIdToRetarget, convertedReference.projectReference) - .AddMetadataReference(projectIdToRetarget, metadataReference); - - solutionChanges.UpdateSolutionForProjectAction(projectIdToRetarget, newSolution); - - referenceInfo.ConvertedProjectReferences.RemoveAt(i); - - // We have converted one, but you could have more than one reference with different aliases - // that we need to convert, so we'll keep going. Make sure to decrement the index so we don't - // skip any items. - i--; - } - } - } - } - - public ProjectReference? TryCreateConvertedProjectReference_NoLock(ProjectId referencingProject, string path, MetadataReferenceProperties properties) - { - // Any conversion to or from project references must be done under the global workspace lock, - // since that needs to be coordinated with updating all projects simultaneously. - Contract.ThrowIfFalse(_gate.CurrentCount == 0); - - if (_projectsByOutputPath.TryGetValue(path, out var ids) && ids.Distinct().Count() == 1) - { - var projectIdToReference = ids.First(); - - if (CanConvertMetadataReferenceToProjectReference(this.CurrentSolution, referencingProject, projectIdToReference)) - { - var projectReference = new ProjectReference( - projectIdToReference, - aliases: properties.Aliases, - embedInteropTypes: properties.EmbedInteropTypes); - - GetReferenceInfo_NoLock(referencingProject).ConvertedProjectReferences.Add((path, projectReference)); - - return projectReference; - } - else - { - return null; - } - } - else - { - return null; - } - } - - public ProjectReference? TryRemoveConvertedProjectReference_NoLock(ProjectId referencingProject, string path, MetadataReferenceProperties properties) - { - // Any conversion to or from project references must be done under the global workspace lock, - // since that needs to be coordinated with updating all projects simultaneously. - Contract.ThrowIfFalse(_gate.CurrentCount == 0); - - var projectReferenceInformation = GetReferenceInfo_NoLock(referencingProject); - foreach (var convertedProject in projectReferenceInformation.ConvertedProjectReferences) - { - if (convertedProject.path == path && - convertedProject.projectReference.EmbedInteropTypes == properties.EmbedInteropTypes && - convertedProject.projectReference.Aliases.SequenceEqual(properties.Aliases)) - { - projectReferenceInformation.ConvertedProjectReferences.Remove(convertedProject); - return convertedProject.projectReference; - } - } - - return null; - } - - public void RemoveProjectOutputPath_NoLock(SolutionChangeAccumulator solutionChanges, ProjectId projectId, string outputPath) - { - Contract.ThrowIfFalse(_gate.CurrentCount == 0); - - var projectReferenceInformation = GetReferenceInfo_NoLock(projectId); - if (!projectReferenceInformation.OutputPaths.Contains(outputPath)) - { - throw new ArgumentException($"Project does not contain output path '{outputPath}'", nameof(outputPath)); - } - - projectReferenceInformation.OutputPaths.Remove(outputPath); - _projectsByOutputPath.MultiRemove(outputPath, projectId); - - // When a project is closed, we may need to convert project references to metadata references (or vice - // versa). Failure to convert the references could leave a project in the workspace with a project - // reference to a project which is not open. - // - // For the specific case where the entire solution is closing, we do not need to update the state for - // remaining projects as each project closes, because we know those projects will be closed without - // further use. Avoiding reference conversion when the solution is closing improves performance for both - // IDE close scenarios and solution reload scenarios that occur after complex branch switches. - if (!_solutionClosing) - { - if (_projectsByOutputPath.TryGetValue(outputPath, out var remainingProjectsForOutputPath)) - { - var distinctRemainingProjects = remainingProjectsForOutputPath.Distinct(); - if (distinctRemainingProjects.Count() == 1) - { - // We had more than one project outputting to the same path. Now we're back down to one - // so we can reference that one again - ConvertMetadataReferencesToProjectReferences_NoLock(solutionChanges, distinctRemainingProjects.Single(), outputPath); - } - } - else - { - // No projects left, we need to convert back to metadata references - ConvertProjectReferencesToMetadataReferences_NoLock(solutionChanges, projectId, outputPath); - } - } - } - - private void StartRefreshingMetadataReferencesForFile(object sender, string fullFilePath) - { + // Try to update the UI context info. But cancel that work if we're shutting down. _threadingContext.RunWithShutdownBlockAsync(async cancellationToken => { - using var asyncToken = _workspaceListener.BeginAsyncOperation(nameof(StartRefreshingMetadataReferencesForFile)); - await ApplyBatchChangeToWorkspaceAsync(solutionChanges => - { - foreach (var project in CurrentSolution.Projects) - { - // Loop to find each reference with the given path. It's possible that there might be multiple references of the same path; - // the project system could concievably add the same reference multiple times but with different aliases. It's also possible - // we might not find the path at all: when we receive the file changed event, we aren't checking if the file is still - // in the workspace at that time; it's possible it might have already been removed. - foreach (var portableExecutableReference in project.MetadataReferences.OfType()) - { - if (portableExecutableReference.FilePath == fullFilePath) - { - FileWatchedReferenceFactory.StopWatchingReference(portableExecutableReference); - - var newPortableExecutableReference = - FileWatchedReferenceFactory.CreateReferenceAndStartWatchingFile( - portableExecutableReference.FilePath, - portableExecutableReference.Properties); - - var newSolution = solutionChanges.Solution.RemoveMetadataReference(project.Id, portableExecutableReference) - .AddMetadataReference(project.Id, newPortableExecutableReference); - - solutionChanges.UpdateSolutionForProjectAction(project.Id, newSolution); - - } - } - } - }).ConfigureAwait(false); + using var asyncToken = _workspaceListener.BeginAsyncOperation(nameof(RefreshProjectExistsUIContextForLanguageAsync)); + await RefreshProjectExistsUIContextForLanguageAsync(project.Language, cancellationToken).ConfigureAwait(false); }); } - [PerformanceSensitive("https://github.com/dotnet/roslyn/issues/54137", AllowLocks = false)] - internal void SetMaxLanguageVersion(ProjectId projectId, string? maxLanguageVersion) - { - ImmutableInterlocked.Update( - ref _projectToMaxSupportedLangVersionMap, - static (map, arg) => map.SetItem(arg.projectId, arg.maxLanguageVersion), - (projectId, maxLanguageVersion)); - } - - [PerformanceSensitive("https://github.com/dotnet/roslyn/issues/54135", AllowLocks = false)] - internal void SetDependencyNodeTargetIdentifier(ProjectId projectId, string targetIdentifier) - { - ImmutableInterlocked.Update( - ref _projectToDependencyNodeTargetIdentifier, - static (map, arg) => map.SetItem(arg.projectId, arg.targetIdentifier), - (projectId, targetIdentifier)); - } - internal async Task RefreshProjectExistsUIContextForLanguageAsync(string language, CancellationToken cancellationToken) { await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: true, cancellationToken); diff --git a/src/VisualStudio/Core/Def/StackTraceExplorer/StackTraceExplorerOptions.cs b/src/VisualStudio/Core/Def/StackTraceExplorer/StackTraceExplorerOptions.cs index 9c4a7d649b75d..8d7a2c88fddd3 100644 --- a/src/VisualStudio/Core/Def/StackTraceExplorer/StackTraceExplorerOptions.cs +++ b/src/VisualStudio/Core/Def/StackTraceExplorer/StackTraceExplorerOptions.cs @@ -2,24 +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.Composition; -using System.Collections.Immutable; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Options.Providers; namespace Microsoft.CodeAnalysis.StackTraceExplorer { internal sealed class StackTraceExplorerOptionsMetadata { - private const string FeatureName = "StackTraceExplorerOptions"; - /// /// Used to determine if a user focusing VS should look at the clipboard for a callstack and automatically /// open the tool window with the callstack inserted /// - public static readonly Option2 OpenOnFocus = new(FeatureName, "OpenOnFocus", defaultValue: false, - storageLocation: new RoamingProfileStorageLocation("StackTraceExplorer.Options.OpenOnFocus")); + public static readonly Option2 OpenOnFocus = new("StackTraceExplorerOptions_OpenOnFocus", defaultValue: false); } } diff --git a/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchGlobalOptions.cs b/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchGlobalOptions.cs index c8fb78a4dd12c..fe37a8f0def74 100644 --- a/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchGlobalOptions.cs +++ b/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchGlobalOptions.cs @@ -8,11 +8,6 @@ namespace Microsoft.CodeAnalysis.SymbolSearch { internal sealed class SymbolSearchGlobalOptions { - private const string LocalRegistryPath = @"Roslyn\Features\SymbolSearch\"; - private const string FeatureName = "SymbolSearchOptions"; - - public static readonly Option2 Enabled = new( - FeatureName, "Enabled", defaultValue: true, - storageLocation: new LocalUserProfileStorageLocation(LocalRegistryPath + "Enabled")); + public static readonly Option2 Enabled = new("SymbolSearchOptions_Enabled", defaultValue: true); } } diff --git a/src/VisualStudio/Core/Def/TableDataSource/TaskList/VisualStudioBaseTaskListTable.cs b/src/VisualStudio/Core/Def/TableDataSource/TaskList/VisualStudioBaseTaskListTable.cs index c0dfc9d3ac113..8c1932e81aaa4 100644 --- a/src/VisualStudio/Core/Def/TableDataSource/TaskList/VisualStudioBaseTaskListTable.cs +++ b/src/VisualStudio/Core/Def/TableDataSource/TaskList/VisualStudioBaseTaskListTable.cs @@ -209,7 +209,13 @@ public override bool TryGetValue(int index, string columnName, [NotNullWhen(true switch (columnName) { case StandardTableKeyNames.Priority: - content = ValueTypeCache.GetOrCreate((VSTASKPRIORITY)data.Priority); + content = ValueTypeCache.GetOrCreate(data.Priority switch + { + TaskListItemPriority.Low => VSTASKPRIORITY.TP_LOW, + TaskListItemPriority.Medium => VSTASKPRIORITY.TP_NORMAL, + TaskListItemPriority.High => VSTASKPRIORITY.TP_HIGH, + _ => VSTASKPRIORITY.TP_NORMAL, + }); return content != null; case StandardTableKeyNames.Text: content = data.Message; diff --git a/src/VisualStudio/Core/Def/TaskList/HostDiagnosticUpdateSource.cs b/src/VisualStudio/Core/Def/TaskList/HostDiagnosticUpdateSource.cs index 43fdb7c0a0e1a..fbc57d001a5ab 100644 --- a/src/VisualStudio/Core/Def/TaskList/HostDiagnosticUpdateSource.cs +++ b/src/VisualStudio/Core/Def/TaskList/HostDiagnosticUpdateSource.cs @@ -127,5 +127,10 @@ public void ClearDiagnosticsForProject(ProjectId projectId, object key) RaiseDiagnosticsRemovedForProject(projectId, key); } } + + public DiagnosticData CreateAnalyzerLoadFailureDiagnostic(AnalyzerLoadFailureEventArgs e, string fullPath, ProjectId projectId, string language) + { + return DocumentAnalysisExecutor.CreateAnalyzerLoadFailureDiagnostic(e, fullPath, projectId, language); + } } } diff --git a/src/VisualStudio/Core/Def/Telemetry/VisualStudioLoggingOptionsMetadata.cs b/src/VisualStudio/Core/Def/Telemetry/VisualStudioLoggingOptionsMetadata.cs index 636411c6dc4a3..a73d24a0cc352 100644 --- a/src/VisualStudio/Core/Def/Telemetry/VisualStudioLoggingOptionsMetadata.cs +++ b/src/VisualStudio/Core/Def/Telemetry/VisualStudioLoggingOptionsMetadata.cs @@ -8,9 +8,6 @@ namespace Microsoft.CodeAnalysis.Diagnostics { internal static class VisualStudioLoggingOptionsMetadata { - private const string LocalRegistryPath = @"Roslyn\Internal\Diagnostics\"; - - public static readonly Option2 EnableFileLoggingForDiagnostics = new("InternalDiagnosticsOptions", "EnableFileLoggingForDiagnostics", defaultValue: false, - storageLocation: new LocalUserProfileStorageLocation(LocalRegistryPath + "EnableFileLoggingForDiagnostics")); + public static readonly Option2 EnableFileLoggingForDiagnostics = new("InternalDiagnosticsOptions_EnableFileLoggingForDiagnostics", defaultValue: false); } } diff --git a/src/VisualStudio/Core/Def/UnusedReferences/Dialog/UnusedReferencesTableProvider.cs b/src/VisualStudio/Core/Def/UnusedReferences/Dialog/UnusedReferencesTableProvider.cs index e72891b70bc5b..3c14a51ac9011 100644 --- a/src/VisualStudio/Core/Def/UnusedReferences/Dialog/UnusedReferencesTableProvider.cs +++ b/src/VisualStudio/Core/Def/UnusedReferences/Dialog/UnusedReferencesTableProvider.cs @@ -44,6 +44,7 @@ public IWpfTableControl4 CreateTableControl() tableControl.ShowGroupingLine = true; tableControl.DoColumnsAutoAdjust = true; tableControl.DoSortingAndGroupingWhileUnstable = true; + tableControl.DoNotLoseFocusOnBucketExpandOrCollapse(); return tableControl; diff --git a/src/VisualStudio/Core/Def/Venus/AbstractContainedLanguage.cs b/src/VisualStudio/Core/Def/Venus/AbstractContainedLanguage.cs deleted file mode 100644 index 626bee6fad80a..0000000000000 --- a/src/VisualStudio/Core/Def/Venus/AbstractContainedLanguage.cs +++ /dev/null @@ -1,24 +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.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Microsoft.VisualStudio.TextManager.Interop; - -namespace Microsoft.VisualStudio.LanguageServices.Implementation.Venus -{ - [Obsolete("This is a compatibility shim for TypeScript; please do not use it.")] - internal sealed class AbstractContainedLanguage - { - public AbstractContainedLanguage(IVsContainedLanguageHost host) - => ContainedLanguageHost = host; - - public IVsContainedLanguageHost ContainedLanguageHost { get; } - } -} diff --git a/src/VisualStudio/Core/Def/Venus/ContainedDocument.cs b/src/VisualStudio/Core/Def/Venus/ContainedDocument.cs index ba376178ca0d2..24e07a5b5eb1d 100644 --- a/src/VisualStudio/Core/Def/Venus/ContainedDocument.cs +++ b/src/VisualStudio/Core/Def/Venus/ContainedDocument.cs @@ -23,6 +23,7 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text.Shared.Extensions; +using Microsoft.CodeAnalysis.Workspaces.ProjectSystem; using Microsoft.VisualStudio.ComponentModelHost; using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; using Microsoft.VisualStudio.Shell.Interop; @@ -37,9 +38,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Venus { -#pragma warning disable CS0618 // Type or member is obsolete - internal sealed partial class ContainedDocument : ForegroundThreadAffinitizedObject, IVisualStudioHostDocument, IContainedDocument -#pragma warning restore CS0618 // Type or member is obsolete + internal sealed partial class ContainedDocument : ForegroundThreadAffinitizedObject, IContainedDocument { private const string ReturnReplacementString = @"{|r|}"; private const string NewLineReplacementString = @"{|n|}"; @@ -87,7 +86,7 @@ public static ContainedDocument TryGetContainedDocument(DocumentId id) private readonly HostType _hostType; private readonly ReiteratedVersionSnapshotTracker _snapshotTracker; private readonly AbstractFormattingRule _vbHelperFormattingRule; - private readonly VisualStudioProject _project; + private readonly ProjectSystemProject _project; public bool SupportsRename { get { return _hostType == HostType.Razor; } } public bool SupportsSemanticSnippets { get { return false; } } @@ -105,7 +104,7 @@ public ContainedDocument( ITextBuffer dataBuffer, IVsTextBufferCoordinator bufferCoordinator, Workspace workspace, - VisualStudioProject project, + ProjectSystemProject project, IComponentModel componentModel, AbstractFormattingRule vbHelperFormattingRule) : base(threadingContext) @@ -128,24 +127,6 @@ public ContainedDocument( s_containedDocuments.TryAdd(documentId, this); } - [Obsolete("This is a compatibility shim for TypeScript; please do not use it.")] - internal AbstractProject Project - { - get - { - return _componentModel.GetService().GetProjectTrackerAndInitializeIfNecessary().GetProject(_project.Id); - } - } - - [Obsolete("This is a compatibility shim for TypeScript; please do not use it.")] - internal AbstractContainedLanguage ContainedLanguage - { - get - { - return new AbstractContainedLanguage(ContainedLanguageHost); - } - } - private HostType GetHostType() { if (DataBuffer is IProjectionBuffer projectionBuffer) diff --git a/src/VisualStudio/Core/Def/Venus/ContainedLanguage.cs b/src/VisualStudio/Core/Def/Venus/ContainedLanguage.cs index 2ac7c7555d8c4..e8b67d2c97d42 100644 --- a/src/VisualStudio/Core/Def/Venus/ContainedLanguage.cs +++ b/src/VisualStudio/Core/Def/Venus/ContainedLanguage.cs @@ -12,6 +12,7 @@ using Microsoft.CodeAnalysis.Formatting.Rules; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Workspaces.ProjectSystem; using Microsoft.VisualStudio.ComponentModelHost; using Microsoft.VisualStudio.Editor; using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; @@ -31,7 +32,7 @@ internal partial class ContainedLanguage protected readonly Workspace Workspace; protected readonly IComponentModel ComponentModel; - public VisualStudioProject? Project { get; } + public ProjectSystemProject? Project { get; } protected readonly ContainedDocument ContainedDocument; @@ -71,7 +72,7 @@ internal ContainedLanguage( IComponentModel componentModel, Workspace workspace, ProjectId projectId, - VisualStudioProject? project, + ProjectSystemProject? project, Guid languageServiceGuid, AbstractFormattingRule? vbHelperFormattingRule = null) { diff --git a/src/VisualStudio/Core/Def/Watson/FaultReporter.cs b/src/VisualStudio/Core/Def/Watson/FaultReporter.cs index 6e1260f69c3d3..21e898b1a5fff 100644 --- a/src/VisualStudio/Core/Def/Watson/FaultReporter.cs +++ b/src/VisualStudio/Core/Def/Watson/FaultReporter.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.Telemetry; using Microsoft.VisualStudio.LanguageServices.Telemetry; using Microsoft.VisualStudio.Telemetry; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ErrorReporting { @@ -130,6 +131,11 @@ public static void ReportFault(Exception exception, FaultSeverity severity, bool { faultUtility.AddFile(path); } + + foreach (var loghubPath in CollectLogHubFilePaths()) + { + faultUtility.AddFile(loghubPath); + } } // Returning "0" signals that, if sampled, we should send data to Watson. @@ -195,57 +201,81 @@ private static string GetDescription(Exception exception) return exception.Message; } - private static List CollectServiceHubLogFilePaths() + private static IList CollectLogHubFilePaths() { - var paths = new List(); + try + { + var logPath = Path.Combine(Path.GetTempPath(), "VSLogs"); + var logs = CollectFilePaths(logPath, "*.svclog", shouldExcludeLogFile: (name) => !name.Contains("Roslyn") && !name.Contains("LSPClient")); + return logs; + } + catch (Exception) + { + // ignore failures + } + return SpecializedCollections.EmptyList(); + } + + private static IList CollectServiceHubLogFilePaths() + { try { var logPath = Path.Combine(Path.GetTempPath(), "servicehub", "logs"); - if (!Directory.Exists(logPath)) - { - return paths; - } - // attach all log files that are modified less than 1 day before. - var now = DateTime.UtcNow; - var oneDay = TimeSpan.FromDays(1); + // TODO: https://github.com/dotnet/roslyn/issues/42582 + // name our services more consistently to simplify filtering + var logs = CollectFilePaths(logPath, "*.log", shouldExcludeLogFile: (name) => !name.Contains("-" + ServiceDescriptor.ServiceNameTopLevelPrefix) && + !name.Contains("-CodeLens") && + !name.Contains("-ManagedLanguage.IDE.RemoteHostClient") && + !name.Contains("-hub")); + return logs; + } + catch (Exception) + { + // ignore failures + } - foreach (var path in Directory.EnumerateFiles(logPath, "*.log")) - { - try - { - var name = Path.GetFileNameWithoutExtension(path); + return SpecializedCollections.EmptyList(); + } - // TODO: https://github.com/dotnet/roslyn/issues/42582 - // name our services more consistently to simplify filtering + private static List CollectFilePaths(string logDirectoryPath, string logFileExtension, Func shouldExcludeLogFile) + { + var paths = new List(); - // filter logs that are not relevant to Roslyn investigation - if (!name.Contains("-" + ServiceDescriptor.ServiceNameTopLevelPrefix) && - !name.Contains("-CodeLens") && - !name.Contains("-ManagedLanguage.IDE.RemoteHostClient") && - !name.Contains("-hub")) - { - continue; - } + if (!Directory.Exists(logDirectoryPath)) + { + return paths; + } - var lastWrite = File.GetLastWriteTimeUtc(path); - if (now - lastWrite > oneDay) - { - continue; - } + // attach all log files that are modified less than 1 day before. + var now = DateTime.UtcNow; + var oneDay = TimeSpan.FromDays(1); - paths.Add(path); + foreach (var path in Directory.EnumerateFiles(logDirectoryPath, logFileExtension)) + { + try + { + var name = Path.GetFileNameWithoutExtension(path); + + // filter logs that are not relevant to Roslyn investigation + if (shouldExcludeLogFile(name)) + { + continue; } - catch + + var lastWrite = File.GetLastWriteTimeUtc(path); + if (now - lastWrite > oneDay) { - // ignore file that can't be accessed + continue; } + + paths.Add(path); + } + catch + { + // ignore file that can't be accessed } - } - catch (Exception) - { - // ignore failures } return paths; diff --git a/src/VisualStudio/Core/Def/Workspace/VisualStudioNavigationOptions.cs b/src/VisualStudio/Core/Def/Workspace/VisualStudioNavigationOptions.cs index 33c9f7ab138f6..83fde90305f30 100644 --- a/src/VisualStudio/Core/Def/Workspace/VisualStudioNavigationOptions.cs +++ b/src/VisualStudio/Core/Def/Workspace/VisualStudioNavigationOptions.cs @@ -2,18 +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.Immutable; -using System.Composition; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Options.Providers; namespace Microsoft.VisualStudio.LanguageServices.Implementation { internal sealed class VisualStudioNavigationOptions { - public static readonly PerLanguageOption2 NavigateToObjectBrowser = new(nameof(VisualStudioNavigationOptions), nameof(NavigateToObjectBrowser), defaultValue: false, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.NavigateToObjectBrowser")); + public static readonly PerLanguageOption2 NavigateToObjectBrowser = new("VisualStudioNavigationOptions_NavigateToObjectBrowser", defaultValue: false); } } diff --git a/src/VisualStudio/Core/Def/Workspace/VisualStudioWorkspaceStatusServiceFactory.cs b/src/VisualStudio/Core/Def/Workspace/VisualStudioWorkspaceStatusServiceFactory.cs index 482a200fb2072..203dd3cc27c69 100644 --- a/src/VisualStudio/Core/Def/Workspace/VisualStudioWorkspaceStatusServiceFactory.cs +++ b/src/VisualStudio/Core/Def/Workspace/VisualStudioWorkspaceStatusServiceFactory.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Immutable; using System.Composition; using System.Threading; using System.Threading.Tasks; @@ -11,23 +10,23 @@ using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Internal.Log; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.ServiceHub.Framework; using Microsoft.VisualStudio.OperationProgress; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Options.Providers; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Threading; -using Task = System.Threading.Tasks.Task; - using IAsyncServiceProvider2 = Microsoft.VisualStudio.Shell.IAsyncServiceProvider2; +using Task = System.Threading.Tasks.Task; namespace Microsoft.VisualStudio.LanguageServices.Implementation { [ExportWorkspaceServiceFactory(typeof(IWorkspaceStatusService), ServiceLayer.Host), Shared] - internal class VisualStudioWorkspaceStatusServiceFactory : IWorkspaceServiceFactory + internal sealed class VisualStudioWorkspaceStatusServiceFactory : IWorkspaceServiceFactory { + private static readonly Option2 s_partialLoadModeFeatureFlag = new("VisualStudioWorkspaceStatusService_PartialLoadModeFeatureFlag", defaultValue: false); + private readonly IAsyncServiceProvider2 _serviceProvider; private readonly IThreadingContext _threadingContext; private readonly IGlobalOptionService _globalOptions; @@ -55,7 +54,7 @@ public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) { if (workspaceServices.Workspace is VisualStudioWorkspace) { - if (!_globalOptions.GetOption(Options.PartialLoadModeFeatureFlag)) + if (!_globalOptions.GetOption(s_partialLoadModeFeatureFlag)) { // don't enable partial load mode for ones that are not in experiment yet return new WorkspaceStatusService(); @@ -182,23 +181,5 @@ public async Task IsFullyLoadedAsync(CancellationToken cancellationToken) return await _progressStageStatus.JoinAsync(cancellationToken).ConfigureAwait(false); } } - - [Export(typeof(IOptionProvider)), Shared] - internal sealed class Options : IOptionProvider - { - private const string FeatureName = "VisualStudioWorkspaceStatusService"; - - public static readonly Option2 PartialLoadModeFeatureFlag = new(FeatureName, nameof(PartialLoadModeFeatureFlag), defaultValue: false, - new FeatureFlagStorageLocation("Roslyn.PartialLoadMode")); - - ImmutableArray IOptionProvider.Options => ImmutableArray.Create( - PartialLoadModeFeatureFlag); - - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public Options() - { - } - } } } diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf index 3d425ec199a5a..b5643d24c12fd 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf @@ -84,7 +84,7 @@ Analyze source generated files - Analyze source generated files + Analyzovat zdrojové soubory. diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf index b76c36cd30fc0..19ddb8a8821df 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf @@ -84,7 +84,7 @@ Analyze source generated files - Analyze source generated files + Analysieren der von der Quelle generierten Dateien diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf index e872d5679da09..bfa5e2348352d 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf @@ -84,7 +84,7 @@ Analyze source generated files - Analyze source generated files + Analizar archivos generados por el origen diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf index 78380a9bab112..cfc1e08ee72c1 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf @@ -84,7 +84,7 @@ Analyze source generated files - Analyze source generated files + Analyser des fichiers générés par la source diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf index 92e1d5277fccb..3efb915d4ad52 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf @@ -84,7 +84,7 @@ Analyze source generated files - Analyze source generated files + Analizza i file generati dall’origine diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf index 2720c0de5d258..4f604ed494006 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf @@ -84,7 +84,7 @@ Analyze source generated files - Analyze source generated files + ソース生成ファイルの分析 diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf index 26b13832078b2..7a8cb1c7d06c3 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf @@ -84,7 +84,7 @@ Analyze source generated files - Analyze source generated files + 소스에서 생성된 파일 분석 diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf index 7a69003e8ed38..f70124d944c0d 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf @@ -84,7 +84,7 @@ Analyze source generated files - Analyze source generated files + Analizuj pliki wygenerowane przez źródło diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf index cd18b6a7912c7..b96e2b442515c 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf @@ -84,7 +84,7 @@ Analyze source generated files - Analyze source generated files + Analisar arquivos gerados pela origem diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf index 7a04ffeeacfdd..583d84aa984bd 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf @@ -84,7 +84,7 @@ Analyze source generated files - Analyze source generated files + Анализ сгенерированного исходного файла diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf index ed175b232bce5..e7ff2e5e8e7e8 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf @@ -84,7 +84,7 @@ Analyze source generated files - Analyze source generated files + Kaynak tarafından oluşturulan dosyaları analiz et diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf index 59dcede54ff4c..678b0257490ec 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf @@ -84,7 +84,7 @@ Analyze source generated files - Analyze source generated files + 分析源生成的文件 @@ -929,7 +929,7 @@ Navigate asynchronously (experimental) - 异步导航(实验性) + 异步导航 (实验性) diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf index e046a1524883e..3e0aa0a7ee291 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf @@ -84,7 +84,7 @@ Analyze source generated files - Analyze source generated files + 分析來源產生的檔案 diff --git a/src/VisualStudio/Core/Impl/Options/AbstractAutomationObject.cs b/src/VisualStudio/Core/Impl/Options/AbstractAutomationObject.cs index 093df9df5d846..68bcd983f7978 100644 --- a/src/VisualStudio/Core/Impl/Options/AbstractAutomationObject.cs +++ b/src/VisualStudio/Core/Impl/Options/AbstractAutomationObject.cs @@ -11,25 +11,33 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options { public abstract class AbstractAutomationObject { - private readonly Workspace _workspace; + private readonly ILegacyGlobalOptionService _legacyGlobalOptions; private readonly string _languageName; - protected AbstractAutomationObject(Workspace workspace, string languageName) - => (_workspace, _languageName) = (workspace, languageName); + internal AbstractAutomationObject(ILegacyGlobalOptionService legacyGlobalOptions, string languageName) + => (_legacyGlobalOptions, _languageName) = (legacyGlobalOptions, languageName); - private protected T GetOption(PerLanguageOption2 key) - => _workspace.Options.GetOption(key, _languageName); + private protected T GetOption(PerLanguageOption2 option) + => _legacyGlobalOptions.GlobalOptions.GetOption(option, _languageName); - private protected void SetOption(PerLanguageOption2 key, T value) - => _workspace.TryApplyChanges(_workspace.CurrentSolution.WithOptions(_workspace.Options - .WithChangedOption(key, _languageName, value))); + private protected void SetOption(PerLanguageOption2 option, T value) + { + _legacyGlobalOptions.GlobalOptions.SetGlobalOption(option, _languageName, value); + + // May be updating an internally-defined public option stored in solution snapshots: + _legacyGlobalOptions.UpdateRegisteredWorkspaces(); + } - private protected T GetOption(Option2 key) - => _workspace.Options.GetOption(key); + private protected T GetOption(Option2 option) + => _legacyGlobalOptions.GlobalOptions.GetOption(option); - private protected void SetOption(Option2 key, T value) - => _workspace.TryApplyChanges(_workspace.CurrentSolution.WithOptions(_workspace.Options - .WithChangedOption(key, value))); + private protected void SetOption(Option2 option, T value) + { + _legacyGlobalOptions.GlobalOptions.SetGlobalOption(option, value); + + // May be updating an internally-defined public option stored in solution snapshots: + _legacyGlobalOptions.UpdateRegisteredWorkspaces(); + } private protected int GetBooleanOption(PerLanguageOption2 key) => NullableBooleanToInteger(GetOption(key)); diff --git a/src/VisualStudio/Core/Impl/Options/AbstractCheckBoxViewModel.cs b/src/VisualStudio/Core/Impl/Options/AbstractCheckBoxViewModel.cs index 3f5d120566d81..3c22acc11f4de 100644 --- a/src/VisualStudio/Core/Impl/Options/AbstractCheckBoxViewModel.cs +++ b/src/VisualStudio/Core/Impl/Options/AbstractCheckBoxViewModel.cs @@ -16,17 +16,17 @@ internal abstract class AbstractCheckBoxViewModel : AbstractNotifyPropertyChange protected bool _isChecked; protected AbstractOptionPreviewViewModel Info { get; } - public IOption Option { get; } + public IOption2 Option { get; } public string Description { get; set; } internal virtual string GetPreview() => _isChecked ? _truePreview : _falsePreview; - public AbstractCheckBoxViewModel(IOption option, string description, string preview, AbstractOptionPreviewViewModel info) + public AbstractCheckBoxViewModel(IOption2 option, string description, string preview, AbstractOptionPreviewViewModel info) : this(option, description, preview, preview, info) { } - public AbstractCheckBoxViewModel(IOption option, string description, string truePreview, string falsePreview, AbstractOptionPreviewViewModel info) + public AbstractCheckBoxViewModel(IOption2 option, string description, string truePreview, string falsePreview, AbstractOptionPreviewViewModel info) { _truePreview = truePreview; _falsePreview = falsePreview; diff --git a/src/VisualStudio/Core/Impl/Options/AbstractOptionPage.cs b/src/VisualStudio/Core/Impl/Options/AbstractOptionPage.cs index beb80cf8653dc..753d90c7b0022 100644 --- a/src/VisualStudio/Core/Impl/Options/AbstractOptionPage.cs +++ b/src/VisualStudio/Core/Impl/Options/AbstractOptionPage.cs @@ -9,13 +9,13 @@ using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.ComponentModelHost; using Microsoft.VisualStudio.Shell; +using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options { [System.ComponentModel.DesignerCategory("code")] // this must be fully qualified internal abstract class AbstractOptionPage : UIElementDialogPage { - private static ILegacyWorkspaceOptionService s_optionService; private static OptionStore s_optionStore; private static bool s_needsToUpdateOptionStore = true; @@ -30,9 +30,7 @@ private void EnsureOptionPageCreated() if (s_optionStore == null) { var componentModel = (IComponentModel)this.Site.GetService(typeof(SComponentModel)); - var workspace = componentModel.GetService(); - s_optionService = workspace.Services.GetService(); - s_optionStore = new OptionStore(new SolutionOptionSet(s_optionService)); + s_optionStore = new OptionStore(componentModel.GetService()); } // Use a single option store for all option pages so that changes are accumulated @@ -57,7 +55,7 @@ protected override void OnActivate(System.ComponentModel.CancelEventArgs e) if (s_needsToUpdateOptionStore) { // Reset the option store to the current state of the options. - s_optionStore.SetOptions(new SolutionOptionSet(s_optionService)); + s_optionStore.Clear(); s_needsToUpdateOptionStore = false; } @@ -107,14 +105,10 @@ public override void SaveSettingsToStorage() // option service. pageControl.OnSave(); - // Save the changes that were accumulated in the option store. - var oldOptions = new SolutionOptionSet(s_optionService); - var newOptions = (SolutionOptionSet)s_optionStore.GetOptions(); + var changedOptions = s_optionStore.GetChangedOptions(); + OptionLogger.Log(changedOptions); - // Must log the option change before setting the new option values via s_optionService, - // otherwise oldOptions and newOptions would be identical and nothing will be logged. - OptionLogger.Log(oldOptions, newOptions); - s_optionService.SetOptions(newOptions, newOptions.GetChangedOptions()); + s_optionStore.GlobalOptions.SetGlobalOptions(changedOptions.SelectAsArray(entry => KeyValuePairUtil.Create(entry.key, entry.newValue))); // Make sure we load the next time a page is activated, in case that options changed // programmatically between now and the next time the page is activated diff --git a/src/VisualStudio/Core/Impl/Options/AbstractOptionPageControl.cs b/src/VisualStudio/Core/Impl/Options/AbstractOptionPageControl.cs index 5482b7a231651..717f0b956dc78 100644 --- a/src/VisualStudio/Core/Impl/Options/AbstractOptionPageControl.cs +++ b/src/VisualStudio/Core/Impl/Options/AbstractOptionPageControl.cs @@ -17,14 +17,14 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options { - [System.ComponentModel.DesignerCategory("code")] // this must be fully qualified + [DesignerCategory("code")] // this must be fully qualified public abstract class AbstractOptionPageControl : UserControl { internal readonly OptionStore OptionStore; private readonly List _bindingExpressions = new List(); private readonly List _searchHandlers = new(); - protected AbstractOptionPageControl(OptionStore optionStore) + private protected AbstractOptionPageControl(OptionStore optionStore) { InitializeStyles(); diff --git a/src/VisualStudio/Core/Impl/Options/AbstractOptionPreviewViewModel.cs b/src/VisualStudio/Core/Impl/Options/AbstractOptionPreviewViewModel.cs index a526cfe418737..aa3cd150b82b6 100644 --- a/src/VisualStudio/Core/Impl/Options/AbstractOptionPreviewViewModel.cs +++ b/src/VisualStudio/Core/Impl/Options/AbstractOptionPreviewViewModel.cs @@ -43,7 +43,6 @@ internal abstract class AbstractOptionPreviewViewModel : AbstractNotifyPropertyC private readonly ITextBufferFactoryService _textBufferFactoryService; private readonly IProjectionBufferFactoryService _projectionBufferFactory; private readonly IContentTypeRegistryService _contentTypeRegistryService; - private readonly IGlobalOptionService _globalOptions; public List Items { get; set; } public ObservableCollection CodeStyleItems { get; set; } @@ -63,33 +62,34 @@ protected AbstractOptionPreviewViewModel(OptionStore optionStore, IServiceProvid _textEditorFactoryService = _componentModel.GetService(); _projectionBufferFactory = _componentModel.GetService(); _editorOptions = _componentModel.GetService(); - _globalOptions = _componentModel.GetService(); this.Language = language; _contentType = _contentTypeRegistryService.GetContentType(ContentTypeNames.CSharpContentType); } - public void SetOptionAndUpdatePreview(T value, IOption option, string preview) + public void SetOptionAndUpdatePreview(T value, IOption2 option, string preview) { - var key = new OptionKey(option, option.IsPerLanguage ? Language : null); + object actualValue; if (option.DefaultValue is ICodeStyleOption codeStyleOption) { // The value provided is either an ICodeStyleOption OR the underlying ICodeStyleOption.Value if (value is ICodeStyleOption newCodeStyleOption) { - OptionStore.SetOption(key, codeStyleOption.WithValue(newCodeStyleOption.Value).WithNotification(newCodeStyleOption.Notification)); + actualValue = codeStyleOption.WithValue(newCodeStyleOption.Value).WithNotification(newCodeStyleOption.Notification); } else { - OptionStore.SetOption(key, codeStyleOption.WithValue(value)); + actualValue = codeStyleOption.WithValue(value); } } else { - OptionStore.SetOption(key, value); + actualValue = value; } + OptionStore.SetOption(option, option.IsPerLanguage ? Language : null, actualValue); + UpdateDocument(preview); } @@ -135,11 +135,9 @@ public void UpdatePreview(string text) project = project.WithMetadataReferences(referenceAssemblies); var document = project.AddDocument("document", SourceText.From(text, Encoding.UTF8)); - var fallbackFormattingOptions = _globalOptions.GetSyntaxFormattingOptions(document.Project.Services); - var optionService = workspace.Services.GetRequiredService(); - var configOptions = OptionStore.GetOptions().AsAnalyzerConfigOptions(optionService, document.Project.Language); + var fallbackFormattingOptions = OptionStore.GlobalOptions.GetSyntaxFormattingOptions(document.Project.Services); var formattingService = document.GetRequiredLanguageService(); - var formattingOptions = formattingService.GetFormattingOptions(configOptions, fallbackFormattingOptions); + var formattingOptions = formattingService.GetFormattingOptions(OptionStore, fallbackFormattingOptions); var formatted = Formatter.FormatAsync(document, formattingOptions, CancellationToken.None).WaitAndGetResult(CancellationToken.None); var textBuffer = _textBufferFactoryService.CreateTextBuffer(formatted.GetTextSynchronously(CancellationToken.None).ToString(), _contentType); @@ -210,7 +208,7 @@ private void UpdateDocument(string text) => UpdatePreview(text); protected void AddParenthesesOption( - string language, OptionStore optionStore, + OptionStore optionStore, PerLanguageOption2> languageOption, string title, string[] examples, bool defaultAddForClarity) { @@ -226,12 +224,12 @@ protected void AddParenthesesOption( isChecked: !defaultAddForClarity)); CodeStyleItems.Add(new EnumCodeStyleOptionViewModel( - languageOption, language, title, preferences.ToArray(), + languageOption, title, preferences.ToArray(), examples, this, optionStore, ServicesVSResources.Parentheses_preferences_colon, codeStylePreferences)); } - protected void AddUnusedParameterOption(string language, OptionStore optionStore, string title, string[] examples) + protected void AddUnusedParameterOption(OptionStore optionStore, string title, string[] examples) { var unusedParameterPreferences = new List { @@ -246,7 +244,7 @@ protected void AddUnusedParameterOption(string language, OptionStore optionStore }; CodeStyleItems.Add(new EnumCodeStyleOptionViewModel( - CodeStyleOptions2.UnusedParameters, language, + CodeStyleOptions2.UnusedParameters, ServicesVSResources.Avoid_unused_parameters, enumValues, examples, this, optionStore, title, unusedParameterPreferences)); diff --git a/src/VisualStudio/Core/Impl/Options/CheckBoxEnumFlagsViewModel.cs b/src/VisualStudio/Core/Impl/Options/CheckBoxEnumFlagsViewModel.cs new file mode 100644 index 0000000000000..a1aa51c4a584d --- /dev/null +++ b/src/VisualStudio/Core/Impl/Options/CheckBoxEnumFlagsViewModel.cs @@ -0,0 +1,86 @@ +// 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.CompilerServices; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Options; + +namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options +{ + internal sealed class CheckBoxEnumFlagsOptionViewModel : AbstractCheckBoxViewModel + where TOptionValue : struct, Enum + { + private readonly int _flag; + private readonly Conversions _conversions; + + /// + /// Stores the latest value of the flags. + /// Shared accross all instances of that represent bits of the same flags enum. + /// + private readonly StrongBox _valueStorage; + + public CheckBoxEnumFlagsOptionViewModel( + IOption2 option, + int flag, + string description, + string preview, + AbstractOptionPreviewViewModel info, + OptionStore optionStore, + StrongBox valueStorage, + Conversions conversions) + : this(option, flag, description, preview, preview, info, optionStore, valueStorage, conversions) + { + } + + public CheckBoxEnumFlagsOptionViewModel( + IOption2 option, + int flag, + string description, + string falsePreview, + string truePreview, + AbstractOptionPreviewViewModel info, + OptionStore optionStore, + StrongBox valueStorage, + Conversions conversions) + : base(option, description, truePreview, falsePreview, info) + { + _valueStorage = valueStorage; + _flag = flag; + _conversions = conversions; + + var flags = optionStore.GetOption(option, option.IsPerLanguage ? info.Language : null); + _valueStorage.Value = flags; + + SetProperty(ref _isChecked, (conversions.To(flags) & flag) == flag); + } + + public override bool IsChecked + { + get + { + return _isChecked; + } + + set + { + SetProperty(ref _isChecked, value); + + var flags = _conversions.To(_valueStorage.Value); + if (value) + { + flags |= _flag; + } + else + { + flags &= ~_flag; + } + + _valueStorage.Value = _conversions.From(flags); + + Info.SetOptionAndUpdatePreview(_valueStorage.Value, Option, GetPreview()); + } + } + } +} diff --git a/src/VisualStudio/Core/Impl/Options/CheckBoxViewModel.cs b/src/VisualStudio/Core/Impl/Options/CheckBoxViewModel.cs index a2ac5f41fe0ad..6bbc748f39188 100644 --- a/src/VisualStudio/Core/Impl/Options/CheckBoxViewModel.cs +++ b/src/VisualStudio/Core/Impl/Options/CheckBoxViewModel.cs @@ -10,15 +10,15 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options { internal class CheckBoxOptionViewModel : AbstractCheckBoxViewModel { - public CheckBoxOptionViewModel(IOption option, string description, string preview, AbstractOptionPreviewViewModel info, OptionStore optionStore) + public CheckBoxOptionViewModel(IOption2 option, string description, string preview, AbstractOptionPreviewViewModel info, OptionStore optionStore) : this(option, description, preview, preview, info, optionStore) { } - public CheckBoxOptionViewModel(IOption option, string description, string truePreview, string falsePreview, AbstractOptionPreviewViewModel info, OptionStore optionStore) + public CheckBoxOptionViewModel(IOption2 option, string description, string truePreview, string falsePreview, AbstractOptionPreviewViewModel info, OptionStore optionStore) : base(option, description, truePreview, falsePreview, info) { - SetProperty(ref _isChecked, (bool)optionStore.GetOption(new OptionKey(option, option.IsPerLanguage ? info.Language : null))); + SetProperty(ref _isChecked, optionStore.GetOption(option, option.IsPerLanguage ? info.Language : null)); } public override bool IsChecked diff --git a/src/VisualStudio/Core/Impl/Options/GridOptionPreviewControl.xaml b/src/VisualStudio/Core/Impl/Options/GridOptionPreviewControl.xaml index 063cedf8d1d23..ed01beac0602f 100644 --- a/src/VisualStudio/Core/Impl/Options/GridOptionPreviewControl.xaml +++ b/src/VisualStudio/Core/Impl/Options/GridOptionPreviewControl.xaml @@ -165,7 +165,7 @@ Grid.Column="0"/> diff --git a/src/VisualStudio/Core/Impl/Options/GridOptionPreviewControl.xaml.cs b/src/VisualStudio/Core/Impl/Options/GridOptionPreviewControl.xaml.cs index 5acd349d92054..15e6727957ab4 100644 --- a/src/VisualStudio/Core/Impl/Options/GridOptionPreviewControl.xaml.cs +++ b/src/VisualStudio/Core/Impl/Options/GridOptionPreviewControl.xaml.cs @@ -30,7 +30,7 @@ internal partial class GridOptionPreviewControl : AbstractOptionPageControl internal AbstractOptionPreviewViewModel ViewModel; private readonly IServiceProvider _serviceProvider; private readonly Func _createViewModel; - private readonly ImmutableArray<(string feature, ImmutableArray options)> _groupedEditorConfigOptions; + private readonly ImmutableArray<(string feature, ImmutableArray options)> _groupedEditorConfigOptions; private readonly string _language; public static readonly Uri CodeStylePageHeaderLearnMoreUri = new Uri(UseEditorConfigUrl); @@ -41,11 +41,12 @@ internal partial class GridOptionPreviewControl : AbstractOptionPageControl public static string SeverityHeader => ServicesVSResources.Severity; public static string GenerateEditorConfigFileFromSettingsText => ServicesVSResources.Generate_dot_editorconfig_file_from_settings; - internal GridOptionPreviewControl(IServiceProvider serviceProvider, + internal GridOptionPreviewControl( + IServiceProvider serviceProvider, OptionStore optionStore, Func createViewModel, - ImmutableArray<(string feature, ImmutableArray options)> groupedEditorConfigOptions, + ImmutableArray<(string feature, ImmutableArray options)> groupedEditorConfigOptions, string language) : base(optionStore) { @@ -57,10 +58,10 @@ internal GridOptionPreviewControl(IServiceProvider serviceProvider, _groupedEditorConfigOptions = groupedEditorConfigOptions; } - internal static IEnumerable<(string feature, ImmutableArray options)> GetLanguageAgnosticEditorConfigOptions() + internal static IEnumerable<(string feature, ImmutableArray options)> GetLanguageAgnosticEditorConfigOptions() { yield return (WorkspacesResources.Core_EditorConfig_Options, FormattingOptions2.Options); - yield return (WorkspacesResources.dot_NET_Coding_Conventions, GenerationOptions.AllOptions.AddRange(CodeStyleOptions2.AllOptions).As()); + yield return (WorkspacesResources.dot_NET_Coding_Conventions, GenerationOptions.AllOptions.AddRange(CodeStyleOptions2.AllOptions)); } private void LearnMoreHyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e) @@ -114,8 +115,7 @@ internal void Generate_Save_EditorConfig(object sender, System.Windows.RoutedEve { Logger.Log(FunctionId.ToolsOptions_GenerateEditorconfig); - var optionSet = this.OptionStore.GetOptions(); - var editorconfig = EditorConfigFileGenerator.Generate(_groupedEditorConfigOptions, optionSet, _language); + var editorconfig = EditorConfigFileGenerator.Generate(_groupedEditorConfigOptions, OptionStore, _language); using (var sfd = new System.Windows.Forms.SaveFileDialog { Filter = "All files (*.*)|", diff --git a/src/VisualStudio/Core/Impl/Options/OptionBinding.cs b/src/VisualStudio/Core/Impl/Options/OptionBinding.cs index ed2b13e599193..e8f2dd766e2ba 100644 --- a/src/VisualStudio/Core/Impl/Options/OptionBinding.cs +++ b/src/VisualStudio/Core/Impl/Options/OptionBinding.cs @@ -12,18 +12,18 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options internal class OptionBinding : INotifyPropertyChanged { private readonly OptionStore _optionStore; - private readonly Option2 _key; + private readonly Option2 _option; public event PropertyChangedEventHandler PropertyChanged; - public OptionBinding(OptionStore optionStore, Option2 key) + public OptionBinding(OptionStore optionStore, Option2 option) { _optionStore = optionStore; - _key = key; + _option = option; _optionStore.OptionChanged += (sender, e) => { - if (e.Option == _key) + if (e.Option == _option) { PropertyChanged?.Raise(this, new PropertyChangedEventArgs(nameof(Value))); } @@ -34,12 +34,12 @@ public T Value { get { - return _optionStore.GetOption(_key); + return _optionStore.GetOption(_option); } set { - _optionStore.SetOption(_key, value); + _optionStore.SetOption(_option, value); } } } diff --git a/src/VisualStudio/Core/Impl/Options/OptionLogger.cs b/src/VisualStudio/Core/Impl/Options/OptionLogger.cs index 569e946bcb607..347158e934aaa 100644 --- a/src/VisualStudio/Core/Impl/Options/OptionLogger.cs +++ b/src/VisualStudio/Core/Impl/Options/OptionLogger.cs @@ -2,8 +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 - +using System.Collections.Immutable; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Options; @@ -11,33 +10,30 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options { internal static class OptionLogger { - private const string Name = nameof(Name); + private const string ConfigName = nameof(ConfigName); private const string Language = nameof(Language); private const string Change = nameof(Change); private const string All = nameof(All); - public static void Log(OptionSet oldOptions, OptionSet newOptions) + public static void Log(ImmutableArray<(OptionKey2 key, object? oldValue, object? newValue)> changedOptions) { - foreach (var optionKey in newOptions.GetChangedOptions(oldOptions)) + foreach (var (optionKey, oldValue, newValue) in changedOptions) { - var oldValue = oldOptions.GetOption(optionKey); - var currentValue = newOptions.GetOption(optionKey); - - Logger.Log(FunctionId.Run_Environment_Options, Create(optionKey, oldValue, currentValue)); + Logger.Log(FunctionId.Run_Environment_Options, Create(optionKey, oldValue, newValue)); } } - private static KeyValueLogMessage Create(OptionKey optionKey, object oldValue, object currentValue) + private static KeyValueLogMessage Create(OptionKey2 optionKey, object? oldValue, object? currentValue) { return KeyValueLogMessage.Create(m => { - m[Name] = optionKey.Option.Name; + m[ConfigName] = optionKey.Option.Definition.ConfigName; m[Language] = optionKey.Language ?? All; m[Change] = CreateOptionValue(oldValue, currentValue); }); } - private static string CreateOptionValue(object oldValue, object currentValue) + private static string CreateOptionValue(object? oldValue, object? currentValue) { var oldString = GetOptionValue(oldValue); var newString = GetOptionValue(currentValue); @@ -45,7 +41,7 @@ private static string CreateOptionValue(object oldValue, object currentValue) return oldString + "->" + newString; } - private static string GetOptionValue(object oldValue) + private static string GetOptionValue(object? oldValue) => oldValue == null ? "[null]" : oldValue.ToString(); } } diff --git a/src/VisualStudio/Core/Impl/Options/OptionPreviewControl.xaml b/src/VisualStudio/Core/Impl/Options/OptionPreviewControl.xaml index a37ea46bb3683..a4564dc8fac4d 100644 --- a/src/VisualStudio/Core/Impl/Options/OptionPreviewControl.xaml +++ b/src/VisualStudio/Core/Impl/Options/OptionPreviewControl.xaml @@ -13,7 +13,7 @@ mc:Ignorable="d" d:DesignHeight="279" d:DesignWidth="514"> - + - /// This class is intended to be used by Option pages. It will provide access to an options - /// from an optionset but will not persist changes automatically. + /// Stores values of options read from global options and values set to these options. + /// Not thread safe. /// - public class OptionStore + internal sealed class OptionStore : IOptionsReader { - public event EventHandler OptionChanged; + public readonly IGlobalOptionService GlobalOptions; + + public event EventHandler? OptionChanged; + + /// + /// Cached values read from global options. + /// + private ImmutableDictionary _globalValues; + + /// + /// Updated values. + /// + private ImmutableDictionary _updatedValues; + + public OptionStore(IGlobalOptionService globalOptions) + { + GlobalOptions = globalOptions; + + _globalValues = ImmutableDictionary.Empty; + _updatedValues = ImmutableDictionary.Empty; + } + + public void Clear() + { + _globalValues = ImmutableDictionary.Empty; + _updatedValues = ImmutableDictionary.Empty; + } - private OptionSet _optionSet; + public ImmutableArray<(OptionKey2 key, object? oldValue, object? newValue)> GetChangedOptions() + => _updatedValues.SelectAsArray(entry => (entry.Key, _globalValues[entry.Key], entry.Value)); - public OptionStore(OptionSet optionSet) + bool IOptionsReader.TryGetOption(OptionKey2 optionKey, out T value) { - _optionSet = optionSet; + value = (T)GetOption(optionKey)!; + return true; } - public object GetOption(OptionKey optionKey) => _optionSet.GetOption(optionKey); - public T GetOption(OptionKey optionKey) => _optionSet.GetOption(optionKey); - internal T GetOption(Option2 option) => _optionSet.GetOption(option); - internal T GetOption(PerLanguageOption2 option, string language) => _optionSet.GetOption(option, language); - public OptionSet GetOptions() => _optionSet; + public T GetOption(Option2 option) + => (T)GetOption(new OptionKey2(option))!; + + public T GetOption(PerLanguageOption2 option, string language) + => (T)GetOption(new OptionKey2(option, language))!; + + public T GetOption(IOption2 option, string? language) + { + Debug.Assert(option.IsPerLanguage == language is not null); + return (T)GetOption(new OptionKey2(option, language))!; + } - public void SetOption(OptionKey optionKey, object value) + private object? GetOption(OptionKey2 optionKey) { - _optionSet = _optionSet.WithChangedOption(optionKey, value); + if (_updatedValues.TryGetValue(optionKey, out var value)) + { + return value; + } - OnOptionChanged(optionKey); + if (_globalValues.TryGetValue(optionKey, out value)) + { + return value; + } + + value = GlobalOptions.GetOption(optionKey); + _globalValues = _globalValues.Add(optionKey, value); + return value; } - internal void SetOption(Option2 option, T value) - => SetOption(new OptionKey(option), value); + public void SetOption(Option2 option, T value) + => SetOption(new OptionKey2(option), value); - internal void SetOption(PerLanguageOption2 option, string language, T value) - => SetOption(new OptionKey(option, language), value); + public void SetOption(PerLanguageOption2 option, string language, T value) + => SetOption(new OptionKey2(option, language), value); - public void SetOptions(OptionSet optionSet) - => _optionSet = optionSet; + public void SetOption(IOption2 option, string? language, object? value) + { + Debug.Assert(option.IsPerLanguage == language is not null); + SetOption(new OptionKey2(option, language), value); + } - private void OnOptionChanged(OptionKey optionKey) - => OptionChanged?.Invoke(this, optionKey); + private void SetOption(OptionKey2 optionKey, object? value) + { + var currentValue = GetOption(optionKey); + if (!Equals(value, currentValue)) + { + _updatedValues = _updatedValues.SetItem(optionKey, value); + OptionChanged?.Invoke(this, optionKey); + } + } } } diff --git a/src/VisualStudio/Core/Impl/Options/PerLanguageOptionBinding.cs b/src/VisualStudio/Core/Impl/Options/PerLanguageOptionBinding.cs index 40779195d4687..533880aaa9c5c 100644 --- a/src/VisualStudio/Core/Impl/Options/PerLanguageOptionBinding.cs +++ b/src/VisualStudio/Core/Impl/Options/PerLanguageOptionBinding.cs @@ -12,20 +12,20 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options internal class PerLanguageOptionBinding : INotifyPropertyChanged { private readonly OptionStore _optionStore; - private readonly PerLanguageOption2 _key; + private readonly PerLanguageOption2 _option; private readonly string _languageName; public event PropertyChangedEventHandler PropertyChanged; - public PerLanguageOptionBinding(OptionStore optionStore, PerLanguageOption2 key, string languageName) + public PerLanguageOptionBinding(OptionStore optionStore, PerLanguageOption2 option, string languageName) { _optionStore = optionStore; - _key = key; + _option = option; _languageName = languageName; _optionStore.OptionChanged += (sender, e) => { - if (e.Option == _key) + if (e.Option == _option) { PropertyChanged?.Raise(this, new PropertyChangedEventArgs(nameof(Value))); } @@ -36,12 +36,12 @@ public T Value { get { - return _optionStore.GetOption(_key, _languageName); + return _optionStore.GetOption(_option, _languageName); } set { - _optionStore.SetOption(_key, _languageName, value); + _optionStore.SetOption(_option, _languageName, value); } } } diff --git a/src/VisualStudio/Core/Impl/Options/RadioButtonViewModel.cs b/src/VisualStudio/Core/Impl/Options/RadioButtonViewModel.cs index 834b88b85f052..5f7f689fdcfcd 100644 --- a/src/VisualStudio/Core/Impl/Options/RadioButtonViewModel.cs +++ b/src/VisualStudio/Core/Impl/Options/RadioButtonViewModel.cs @@ -8,13 +8,13 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options { - internal class RadioButtonViewModel : AbstractRadioButtonViewModel + internal class RadioButtonViewModel : AbstractRadioButtonViewModel { - private readonly Option2 _option; - private readonly TOption _value; + private readonly Option2 _option; + private readonly TOptionValue _value; - public RadioButtonViewModel(string description, string preview, string group, TOption value, Option2 option, AbstractOptionPreviewViewModel info, OptionStore optionStore) - : base(description, preview, info, isChecked: optionStore.GetOption(option).Equals(value), group: group) + public RadioButtonViewModel(string description, string preview, string group, TOptionValue value, Option2 option, AbstractOptionPreviewViewModel info, OptionStore optionStore) + : base(description, preview, info, isChecked: optionStore.GetOption(option).Equals(value), group: group) { _value = value; _option = option; diff --git a/src/VisualStudio/Core/Impl/Options/Style/AbstractCodeStyleOptionViewModel.cs b/src/VisualStudio/Core/Impl/Options/Style/AbstractCodeStyleOptionViewModel.cs index 637fa79a7a544..23a9925ee101f 100644 --- a/src/VisualStudio/Core/Impl/Options/Style/AbstractCodeStyleOptionViewModel.cs +++ b/src/VisualStudio/Core/Impl/Options/Style/AbstractCodeStyleOptionViewModel.cs @@ -28,7 +28,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options internal abstract class AbstractCodeStyleOptionViewModel : AbstractNotifyPropertyChanged { protected AbstractOptionPreviewViewModel Info { get; } - public IOption Option { get; } + public IOption2 Option { get; } public string Description { get; set; } public double DescriptionMargin { get; set; } = 12d; @@ -47,7 +47,7 @@ public virtual NotificationOptionViewModel SelectedNotificationPreference } public AbstractCodeStyleOptionViewModel( - IOption option, + IOption2 option, string description, AbstractOptionPreviewViewModel info, string groupName, diff --git a/src/VisualStudio/Core/Impl/Options/Style/BooleanCodeStyleOptionViewModel.cs b/src/VisualStudio/Core/Impl/Options/Style/BooleanCodeStyleOptionViewModel.cs index faf9be7e4e112..0f4b482f1e51e 100644 --- a/src/VisualStudio/Core/Impl/Options/Style/BooleanCodeStyleOptionViewModel.cs +++ b/src/VisualStudio/Core/Impl/Options/Style/BooleanCodeStyleOptionViewModel.cs @@ -24,7 +24,7 @@ internal class BooleanCodeStyleOptionViewModel : AbstractCodeStyleOptionViewMode private NotificationOptionViewModel _selectedNotificationPreference; public BooleanCodeStyleOptionViewModel( - IOption option, + IOption2 option, string description, string truePreview, string falsePreview, @@ -38,8 +38,8 @@ public BooleanCodeStyleOptionViewModel( _truePreview = truePreview; _falsePreview = falsePreview; - var codeStyleOption = (ICodeStyleOption)optionStore.GetOption(new OptionKey(option, option.IsPerLanguage ? info.Language : null)); - _selectedPreference = Preferences.Single(c => c.IsChecked == (bool)codeStyleOption.Value); + var codeStyleOption = optionStore.GetOption>(option, option.IsPerLanguage ? info.Language : null); + _selectedPreference = Preferences.Single(c => c.IsChecked == codeStyleOption.Value); var notificationViewModel = NotificationPreferences.Single(i => i.Notification.Severity == codeStyleOption.Notification.Severity); _selectedNotificationPreference = NotificationPreferences.Single(p => p.Notification.Severity == notificationViewModel.Notification.Severity); diff --git a/src/VisualStudio/Core/Impl/Options/Style/EnumCodeStyleOptionViewModel.cs b/src/VisualStudio/Core/Impl/Options/Style/EnumCodeStyleOptionViewModel.cs index c6a6742f38202..de55f05a1e7ae 100644 --- a/src/VisualStudio/Core/Impl/Options/Style/EnumCodeStyleOptionViewModel.cs +++ b/src/VisualStudio/Core/Impl/Options/Style/EnumCodeStyleOptionViewModel.cs @@ -36,37 +36,7 @@ static EnumCodeStyleOptionViewModel() private NotificationOptionViewModel _selectedNotificationPreference; public EnumCodeStyleOptionViewModel( - PerLanguageOption2> option, - string language, - string description, - T[] enumValues, - string[] previews, - AbstractOptionPreviewViewModel info, - OptionStore optionStore, - string groupName, - List preferences) - : this((IOption)option, language, description, enumValues, previews, info, - optionStore, groupName, preferences) - { - } - - public EnumCodeStyleOptionViewModel( - Option2> option, - string description, - T[] enumValues, - string[] previews, - AbstractOptionPreviewViewModel info, - OptionStore optionStore, - string groupName, - List preferences) - : this(option, language: null, description, enumValues, previews, info, - optionStore, groupName, preferences) - { - } - - private EnumCodeStyleOptionViewModel( - IOption option, - string language, + IOption2 option, string description, T[] enumValues, string[] previews, @@ -82,9 +52,9 @@ private EnumCodeStyleOptionViewModel( _enumValues = enumValues.ToImmutableArray(); _previews = previews.ToImmutableArray(); - var codeStyleOption = (ICodeStyleOption)optionStore.GetOption(new OptionKey(option, language)); + var codeStyleOption = optionStore.GetOption>(option, option.IsPerLanguage ? info.Language : null); - var enumIndex = _enumValues.IndexOf((T)codeStyleOption.Value); + var enumIndex = _enumValues.IndexOf(codeStyleOption.Value); if (enumIndex < 0 || enumIndex >= Preferences.Count) { enumIndex = 0; 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 1346bc21f1827..983d1474bfea5 100644 --- a/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/NamingStyleOptionPageControl.xaml.cs +++ b/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/NamingStyleOptionPageControl.xaml.cs @@ -182,7 +182,7 @@ internal override void OnLoad() { base.OnLoad(); - var preferences = OptionStore.GetOption(NamingStyleOptions.NamingPreferences, _languageName); + var preferences = OptionStore.GetOption(NamingStyleOptions.NamingPreferences, _languageName); if (preferences == null) { return; diff --git a/src/VisualStudio/Core/Impl/ProjectSystem/CPS/CPSProject_IProjectCodeModelProvider.cs b/src/VisualStudio/Core/Impl/ProjectSystem/CPS/CPSProject_IProjectCodeModelProvider.cs index 0f6492f48bcb9..40717cce6d206 100644 --- a/src/VisualStudio/Core/Impl/ProjectSystem/CPS/CPSProject_IProjectCodeModelProvider.cs +++ b/src/VisualStudio/Core/Impl/ProjectSystem/CPS/CPSProject_IProjectCodeModelProvider.cs @@ -46,7 +46,7 @@ EnvDTE.FileCodeModel ICodeModelInstanceFactory.TryCreateFileCodeModelThroughProj private EnvDTE.ProjectItem GetProjectItem(string filePath) { - var dteProject = _project._visualStudioWorkspace.TryGetDTEProject(_project._visualStudioProject.Id); + var dteProject = _project._visualStudioWorkspace.TryGetDTEProject(_project._projectSystemProject.Id); if (dteProject == null) { return null; diff --git a/src/VisualStudio/Core/Impl/ProjectSystem/CPS/CPSProject_IWorkspaceProjectContext.cs b/src/VisualStudio/Core/Impl/ProjectSystem/CPS/CPSProject_IWorkspaceProjectContext.cs index 60600e4dad016..318bd65d6fbc7 100644 --- a/src/VisualStudio/Core/Impl/ProjectSystem/CPS/CPSProject_IWorkspaceProjectContext.cs +++ b/src/VisualStudio/Core/Impl/ProjectSystem/CPS/CPSProject_IWorkspaceProjectContext.cs @@ -11,6 +11,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Workspaces.ProjectSystem; using Microsoft.VisualStudio.LanguageServices.Implementation.CodeModel; using Microsoft.VisualStudio.LanguageServices.Implementation.TaskList; using Microsoft.VisualStudio.LanguageServices.ProjectSystem; @@ -20,7 +21,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.C { internal sealed partial class CPSProject : IWorkspaceProjectContext { - private readonly VisualStudioProject _visualStudioProject; + private readonly ProjectSystemProject _projectSystemProject; /// /// The we're using to parse command line options. Null if we don't @@ -32,24 +33,24 @@ internal sealed partial class CPSProject : IWorkspaceProjectContext private readonly IProjectCodeModel _projectCodeModel; private readonly Lazy _externalErrorReporter; - private readonly ConcurrentQueue _batchScopes = new(); + private readonly ConcurrentQueue _batchScopes = new(); public string DisplayName { - get => _visualStudioProject.DisplayName; - set => _visualStudioProject.DisplayName = value; + get => _projectSystemProject.DisplayName; + set => _projectSystemProject.DisplayName = value; } public string? ProjectFilePath { - get => _visualStudioProject.FilePath; - set => _visualStudioProject.FilePath = value; + get => _projectSystemProject.FilePath; + set => _projectSystemProject.FilePath = value; } public bool IsPrimary { - get => _visualStudioProject.IsPrimary; - set => _visualStudioProject.IsPrimary = value; + get => _projectSystemProject.IsPrimary; + set => _projectSystemProject.IsPrimary = value; } public Guid Guid @@ -60,18 +61,18 @@ public Guid Guid public bool LastDesignTimeBuildSucceeded { - get => _visualStudioProject.HasAllInformation; - set => _visualStudioProject.HasAllInformation = value; + get => _projectSystemProject.HasAllInformation; + set => _projectSystemProject.HasAllInformation = value; } - public CPSProject(VisualStudioProject visualStudioProject, VisualStudioWorkspaceImpl visualStudioWorkspace, IProjectCodeModelFactory projectCodeModelFactory, Guid projectGuid) + public CPSProject(ProjectSystemProject projectSystemProject, VisualStudioWorkspaceImpl visualStudioWorkspace, IProjectCodeModelFactory projectCodeModelFactory, Guid projectGuid) { - _visualStudioProject = visualStudioProject; + _projectSystemProject = projectSystemProject; _visualStudioWorkspace = visualStudioWorkspace; _externalErrorReporter = new Lazy(() => { - var prefix = visualStudioProject.Language switch + var prefix = projectSystemProject.Language switch { LanguageNames.CSharp => "CS", LanguageNames.VisualBasic => "BC", @@ -79,17 +80,17 @@ public CPSProject(VisualStudioProject visualStudioProject, VisualStudioWorkspace _ => null }; - return (prefix != null) ? new ProjectExternalErrorReporter(visualStudioProject.Id, prefix, visualStudioProject.Language, visualStudioWorkspace) : null; + return (prefix != null) ? new ProjectExternalErrorReporter(projectSystemProject.Id, prefix, projectSystemProject.Language, visualStudioWorkspace) : null; }); - _projectCodeModel = projectCodeModelFactory.CreateProjectCodeModel(visualStudioProject.Id, new CPSCodeModelInstanceFactory(this)); + _projectCodeModel = projectCodeModelFactory.CreateProjectCodeModel(projectSystemProject.Id, new CPSCodeModelInstanceFactory(this)); // If we have a command line parser service for this language, also set up our ability to process options if they come in - if (visualStudioWorkspace.Services.GetLanguageServices(visualStudioProject.Language).GetService() != null) + if (visualStudioWorkspace.Services.GetLanguageServices(projectSystemProject.Language).GetService() != null) { - _visualStudioProjectOptionsProcessor = new VisualStudioProjectOptionsProcessor(_visualStudioProject, visualStudioWorkspace.Services.SolutionServices); + _visualStudioProjectOptionsProcessor = new VisualStudioProjectOptionsProcessor(_projectSystemProject, visualStudioWorkspace.Services.SolutionServices); _visualStudioWorkspace.AddProjectRuleSetFileToInternalMaps( - visualStudioProject, + projectSystemProject, () => _visualStudioProjectOptionsProcessor.EffectiveRuleSetFilePath); } @@ -98,13 +99,13 @@ public CPSProject(VisualStudioProject visualStudioProject, VisualStudioWorkspace public string? BinOutputPath { - get => _visualStudioProject.OutputFilePath; + get => _projectSystemProject.OutputFilePath; set { // If we don't have a path, always set it to null if (string.IsNullOrEmpty(value)) { - _visualStudioProject.OutputFilePath = null; + _projectSystemProject.OutputFilePath = null; return; } @@ -113,26 +114,26 @@ public string? BinOutputPath // can be removed now, but we still have tests asserting it. if (!PathUtilities.IsAbsolute(value)) { - var rootDirectory = _visualStudioProject.FilePath != null - ? Path.GetDirectoryName(_visualStudioProject.FilePath) + var rootDirectory = _projectSystemProject.FilePath != null + ? Path.GetDirectoryName(_projectSystemProject.FilePath) : Path.GetTempPath(); - _visualStudioProject.OutputFilePath = Path.Combine(rootDirectory, value); + _projectSystemProject.OutputFilePath = Path.Combine(rootDirectory, value); } else { - _visualStudioProject.OutputFilePath = value; + _projectSystemProject.OutputFilePath = value; } } } internal string? CompilationOutputAssemblyFilePath { - get => _visualStudioProject.CompilationOutputAssemblyFilePath; - set => _visualStudioProject.CompilationOutputAssemblyFilePath = value; + get => _projectSystemProject.CompilationOutputAssemblyFilePath; + set => _projectSystemProject.CompilationOutputAssemblyFilePath = value; } - public ProjectId Id => _visualStudioProject.Id; + public ProjectId Id => _projectSystemProject.Id; public void SetOptions(string commandLineForOptions) => _visualStudioProjectOptionsProcessor?.SetCommandLine(commandLineForOptions); @@ -149,32 +150,32 @@ public void SetProperty(string name, string? value) // use it for their own purpose. // In the future, we might consider officially exposing "default namespace" for VB project // (e.g. through a msbuild property) - _visualStudioProject.DefaultNamespace = value; + _projectSystemProject.DefaultNamespace = value; } else if (name == BuildPropertyNames.MaxSupportedLangVersion) { - _visualStudioProject.MaxLangVersion = value; + _projectSystemProject.MaxLangVersion = value; } else if (name == BuildPropertyNames.RunAnalyzers) { var boolValue = bool.TryParse(value, out var parsedBoolValue) ? parsedBoolValue : (bool?)null; - _visualStudioProject.RunAnalyzers = boolValue; + _projectSystemProject.RunAnalyzers = boolValue; } else if (name == BuildPropertyNames.RunAnalyzersDuringLiveAnalysis) { var boolValue = bool.TryParse(value, out var parsedBoolValue) ? parsedBoolValue : (bool?)null; - _visualStudioProject.RunAnalyzersDuringLiveAnalysis = boolValue; + _projectSystemProject.RunAnalyzersDuringLiveAnalysis = boolValue; } else if (name == BuildPropertyNames.TemporaryDependencyNodeTargetIdentifier && !RoslynString.IsNullOrEmpty(value)) { - _visualStudioProject.DependencyNodeTargetIdentifier = value; + _projectSystemProject.DependencyNodeTargetIdentifier = value; } else if (name == BuildPropertyNames.TargetRefPath) { // If we don't have a path, always set it to null if (string.IsNullOrEmpty(value)) { - _visualStudioProject.OutputRefFilePath = null; + _projectSystemProject.OutputRefFilePath = null; } else { @@ -183,15 +184,15 @@ public void SetProperty(string name, string? value) // can be removed now, but we still have tests asserting it. if (!PathUtilities.IsAbsolute(value)) { - var rootDirectory = _visualStudioProject.FilePath != null - ? Path.GetDirectoryName(_visualStudioProject.FilePath) + var rootDirectory = _projectSystemProject.FilePath != null + ? Path.GetDirectoryName(_projectSystemProject.FilePath) : Path.GetTempPath(); - _visualStudioProject.OutputRefFilePath = Path.Combine(rootDirectory, value); + _projectSystemProject.OutputRefFilePath = Path.Combine(rootDirectory, value); } else { - _visualStudioProject.OutputRefFilePath = value; + _projectSystemProject.OutputRefFilePath = value; } } } @@ -200,64 +201,64 @@ public void SetProperty(string name, string? value) public void AddMetadataReference(string referencePath, MetadataReferenceProperties properties) { referencePath = FileUtilities.NormalizeAbsolutePath(referencePath); - _visualStudioProject.AddMetadataReference(referencePath, properties); + _projectSystemProject.AddMetadataReference(referencePath, properties); } public void RemoveMetadataReference(string referencePath) { referencePath = FileUtilities.NormalizeAbsolutePath(referencePath); - _visualStudioProject.RemoveMetadataReference(referencePath, _visualStudioProject.GetPropertiesForMetadataReference(referencePath).Single()); + _projectSystemProject.RemoveMetadataReference(referencePath, _projectSystemProject.GetPropertiesForMetadataReference(referencePath).Single()); } public void AddProjectReference(IWorkspaceProjectContext project, MetadataReferenceProperties properties) { - var otherProjectId = ((CPSProject)project)._visualStudioProject.Id; - _visualStudioProject.AddProjectReference(new ProjectReference(otherProjectId, properties.Aliases, properties.EmbedInteropTypes)); + var otherProjectId = ((CPSProject)project)._projectSystemProject.Id; + _projectSystemProject.AddProjectReference(new ProjectReference(otherProjectId, properties.Aliases, properties.EmbedInteropTypes)); } public void RemoveProjectReference(IWorkspaceProjectContext project) { - var otherProjectId = ((CPSProject)project)._visualStudioProject.Id; - var otherProjectReference = _visualStudioProject.GetProjectReferences().Single(pr => pr.ProjectId == otherProjectId); - _visualStudioProject.RemoveProjectReference(otherProjectReference); + var otherProjectId = ((CPSProject)project)._projectSystemProject.Id; + var otherProjectReference = _projectSystemProject.GetProjectReferences().Single(pr => pr.ProjectId == otherProjectId); + _projectSystemProject.RemoveProjectReference(otherProjectReference); } public void AddSourceFile(string filePath, bool isInCurrentContext = true, IEnumerable? folderNames = null, SourceCodeKind sourceCodeKind = SourceCodeKind.Regular) - => _visualStudioProject.AddSourceFile(filePath, sourceCodeKind, folderNames.AsImmutableOrNull()); + => _projectSystemProject.AddSourceFile(filePath, sourceCodeKind, folderNames.AsImmutableOrNull()); public void RemoveSourceFile(string filePath) { - _visualStudioProject.RemoveSourceFile(filePath); + _projectSystemProject.RemoveSourceFile(filePath); _projectCodeModel.OnSourceFileRemoved(filePath); } public void AddAdditionalFile(string filePath, bool isInCurrentContext = true) - => _visualStudioProject.AddAdditionalFile(filePath); + => _projectSystemProject.AddAdditionalFile(filePath); public void Dispose() { _projectCodeModel?.OnProjectClosed(); _visualStudioProjectOptionsProcessor?.Dispose(); - _visualStudioProject.RemoveFromWorkspace(); + _projectSystemProject.RemoveFromWorkspace(); } public void AddAnalyzerReference(string referencePath) - => _visualStudioProject.AddAnalyzerReference(referencePath); + => _projectSystemProject.AddAnalyzerReference(referencePath); public void RemoveAnalyzerReference(string referencePath) - => _visualStudioProject.RemoveAnalyzerReference(referencePath); + => _projectSystemProject.RemoveAnalyzerReference(referencePath); public void RemoveAdditionalFile(string filePath) - => _visualStudioProject.RemoveAdditionalFile(filePath); + => _projectSystemProject.RemoveAdditionalFile(filePath); public void AddDynamicFile(string filePath, IEnumerable? folderNames = null) - => _visualStudioProject.AddDynamicSourceFile(filePath, folderNames.ToImmutableArrayOrEmpty()); + => _projectSystemProject.AddDynamicSourceFile(filePath, folderNames.ToImmutableArrayOrEmpty()); public void RemoveDynamicFile(string filePath) - => _visualStudioProject.RemoveDynamicSourceFile(filePath); + => _projectSystemProject.RemoveDynamicSourceFile(filePath); public void StartBatch() - => _batchScopes.Enqueue(_visualStudioProject.CreateBatchScope()); + => _batchScopes.Enqueue(_projectSystemProject.CreateBatchScope()); public ValueTask EndBatchAsync() { @@ -266,17 +267,17 @@ public ValueTask EndBatchAsync() } public void ReorderSourceFiles(IEnumerable? filePaths) - => _visualStudioProject.ReorderSourceFiles(filePaths.ToImmutableArrayOrEmpty()); + => _projectSystemProject.ReorderSourceFiles(filePaths.ToImmutableArrayOrEmpty()); - internal VisualStudioProject GetProject_TestOnly() - => _visualStudioProject; + internal ProjectSystemProject GetProject_TestOnly() + => _projectSystemProject; public void AddAnalyzerConfigFile(string filePath) - => _visualStudioProject.AddAnalyzerConfigFile(filePath); + => _projectSystemProject.AddAnalyzerConfigFile(filePath); public void RemoveAnalyzerConfigFile(string filePath) - => _visualStudioProject.RemoveAnalyzerConfigFile(filePath); + => _projectSystemProject.RemoveAnalyzerConfigFile(filePath); - public IAsyncDisposable CreateBatchScope() => _visualStudioProject.CreateBatchScope(); + public IAsyncDisposable CreateBatchScope() => _projectSystemProject.CreateBatchScope(); } } diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/CpsDiagnosticItemSource.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/CpsDiagnosticItemSource.cs index 804f0840c8c7b..41eb9357fd5c9 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/CpsDiagnosticItemSource.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/CpsDiagnosticItemSource.cs @@ -18,6 +18,9 @@ internal partial class CpsDiagnosticItemSource : BaseDiagnosticAndGeneratorItemS private readonly IVsHierarchyItem _item; private readonly string _projectDirectoryPath; + /// + /// The analyzer reference that has been found. Once it's been assigned a non-null value, it'll never be assigned null again. + /// private AnalyzerReference? _analyzerReference; public event PropertyChangedEventHandler? PropertyChanged; @@ -31,9 +34,38 @@ public CpsDiagnosticItemSource(Workspace workspace, string projectPath, ProjectI _analyzerReference = TryGetAnalyzerReference(Workspace.CurrentSolution); if (_analyzerReference == null) { - // The workspace doesn't know about the project and/or the analyzer yet. - // Hook up an event handler so we can update when it does. - Workspace.WorkspaceChanged += OnWorkspaceChangedLookForAnalyzer; + // The ProjectId that was given to us was found by enumerating the list of projects in the solution, thus the project must have already + // been added to the workspace at some point. As long as the project is still there, we're going to assume the reason we don't have the reference + // yet is because while we have a project, we don't have all the references added yet. We'll wait until we see the reference and then connect to it. + if (workspace.CurrentSolution.ContainsProject(projectId)) + { + Workspace.WorkspaceChanged += OnWorkspaceChangedLookForAnalyzer; + item.PropertyChanged += IVsHierarchyItem_PropertyChanged; + + // Now that we've subscribed, check once more in case we missed the event + var analyzerReference = TryGetAnalyzerReference(Workspace.CurrentSolution); + + if (analyzerReference != null) + { + _analyzerReference = analyzerReference; + UnsubscribeFromEvents(); + } + } + } + } + + private void UnsubscribeFromEvents() + { + Workspace.WorkspaceChanged -= OnWorkspaceChangedLookForAnalyzer; + _item.PropertyChanged -= IVsHierarchyItem_PropertyChanged; + } + + private void IVsHierarchyItem_PropertyChanged(object sender, PropertyChangedEventArgs e) + { + // IVsHierarchyItem implements ISupportDisposalNotification, which allows us to know when it's been removed + if (e.PropertyName == nameof(ISupportDisposalNotification.IsDisposed)) + { + UnsubscribeFromEvents(); } } @@ -45,38 +77,24 @@ public CpsDiagnosticItemSource(Workspace workspace, string projectPath, ProjectI private void OnWorkspaceChangedLookForAnalyzer(object sender, WorkspaceChangeEventArgs e) { - if (e.Kind is WorkspaceChangeKind.SolutionCleared or - WorkspaceChangeKind.SolutionReloaded or - WorkspaceChangeKind.SolutionRemoved) + // If the project has gone away in this change, it's not coming back, so we can stop looking at this point + if (!e.NewSolution.ContainsProject(ProjectId)) { - Workspace.WorkspaceChanged -= OnWorkspaceChangedLookForAnalyzer; + UnsubscribeFromEvents(); + return; } - else if (e.Kind == WorkspaceChangeKind.SolutionAdded) - { - _analyzerReference = TryGetAnalyzerReference(e.NewSolution); - if (_analyzerReference != null) - { - Workspace.WorkspaceChanged -= OnWorkspaceChangedLookForAnalyzer; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(HasItems))); - } - } - else if (e.ProjectId == ProjectId) + // Was this a change to our project, or a global change? + if (e.ProjectId == ProjectId || + e.Kind == WorkspaceChangeKind.SolutionChanged) { - if (e.Kind == WorkspaceChangeKind.ProjectRemoved) - { - Workspace.WorkspaceChanged -= OnWorkspaceChangedLookForAnalyzer; - } - else if (e.Kind is WorkspaceChangeKind.ProjectAdded - or WorkspaceChangeKind.ProjectChanged) + var analyzerReference = TryGetAnalyzerReference(e.NewSolution); + if (analyzerReference != null) { - _analyzerReference = TryGetAnalyzerReference(e.NewSolution); - if (_analyzerReference != null) - { - Workspace.WorkspaceChanged -= OnWorkspaceChangedLookForAnalyzer; + _analyzerReference = analyzerReference; + UnsubscribeFromEvents(); - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(HasItems))); - } + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(HasItems))); } } } diff --git a/src/VisualStudio/Core/Test.Next/Options/VisualStudioOptionStorageTests.cs b/src/VisualStudio/Core/Test.Next/Options/VisualStudioOptionStorageTests.cs new file mode 100644 index 0000000000000..634c0b83c315e --- /dev/null +++ b/src/VisualStudio/Core/Test.Next/Options/VisualStudioOptionStorageTests.cs @@ -0,0 +1,136 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using Xunit; +using Microsoft.VisualStudio.LanguageServices.Options; +using Roslyn.Test.Utilities; +using Microsoft.CodeAnalysis.Options; + +namespace Microsoft.CodeAnalysis.UnitTests; + +public class VisualStudioOptionStorageTests +{ + [Fact] + public void OptionValidation() + { + var storages = VisualStudioOptionStorage.Storages; + var infos = OptionsTestInfo.CollectOptions(Path.GetDirectoryName(typeof(VisualStudioOptionStorage).Assembly.Location)); + + // Options with per-language values shouldn't be defined in langauge-specific assembly since then they wouldn't be applicable to the other language. + + var perLanguageOptionsDefinedInIncorrectAssembly = + from info in infos + where info.Value.Option.IsPerLanguage && info.Value.ContainingAssemblyLanguage is "CSharp" or "VisualBasic" + select info; + + Assert.Empty(perLanguageOptionsDefinedInIncorrectAssembly); + + // languge specific options have correct name prefix and are defined in language specific assemblies: + + var languageSpecificOptionsHaveIncorrectPrefix = + from info in infos + where info.Value.Option is not IPublicOption // public options do not need to follow the naming pattern + where info.Value.Option.Definition.IsEditorConfigOption // TODO: remove condition once all options have config name https://github.com/dotnet/roslyn/issues/65787 + where info.Key.StartsWith(OptionDefinition.CSharpConfigNamePrefix, StringComparison.Ordinal) != info.Value.ContainingAssemblyLanguage is "CSharp" || + info.Key.StartsWith(OptionDefinition.VisualBasicConfigNamePrefix, StringComparison.Ordinal) != info.Value.ContainingAssemblyLanguage is "VisualBasic" + select (info); + + Assert.Empty(languageSpecificOptionsHaveIncorrectPrefix); + + // each option that has associated public option is exposed via a public accessor + + var publicOptionsWithoutPublicAccessor = + from info in infos + where info.Value.Accessors.Any(a => a.option.PublicOption != null) + where !info.Value.Accessors.Any(a => a.isPublic) + select info.Key; + + Assert.Empty(publicOptionsWithoutPublicAccessor); + + // no two option names map to the same storage (however, there may be multiple option definitions that share the same option name and storage): + + var duplicateRoamingProfileStorages = + from storage in storages + let roamingStorageKey = storage.Value is VisualStudioOptionStorage.RoamingProfileStorage { Key: var key } ? key : null + where roamingStorageKey is not null + group storage.Key by roamingStorageKey into g + where g.Count() > 1 + select string.Join(",", g); + + Assert.Empty(duplicateRoamingProfileStorages); + + // each storage is used by an option: + + var unusedStorageMappings = + from configName in storages.Keys + where !infos.ContainsKey(configName) + select configName; + + Assert.Empty(unusedStorageMappings); + + // following options have no VS storage (update upon adding new storage-less option): + + var optionsWithoutStorage = + from info in infos + where !storages.ContainsKey(info.Key) + orderby info.Key + select info.Key; + + AssertEx.Equal(new[] + { + "CompletionOptions_ForceExpandedCompletionIndexCreation", // test-only option + "CSharpFormattingOptions_NewLinesForBracesInAccessors", // public option deserialized via CSharpVisualStudioOptionStorageReadFallbacks + "CSharpFormattingOptions_NewLinesForBracesInAnonymousMethods", // public option deserialized via CSharpVisualStudioOptionStorageReadFallbacks + "CSharpFormattingOptions_NewLinesForBracesInAnonymousTypes", // public option deserialized via CSharpVisualStudioOptionStorageReadFallbacks + "CSharpFormattingOptions_NewLinesForBracesInControlBlocks", // public option deserialized via CSharpVisualStudioOptionStorageReadFallbacks + "CSharpFormattingOptions_NewLinesForBracesInLambdaExpressionBody", // public option deserialized via CSharpVisualStudioOptionStorageReadFallbacks + "CSharpFormattingOptions_NewLinesForBracesInMethods", // public option deserialized via CSharpVisualStudioOptionStorageReadFallbacks + "CSharpFormattingOptions_NewLinesForBracesInObjectCollectionArrayInitializers", // public option deserialized via CSharpVisualStudioOptionStorageReadFallbacks + "CSharpFormattingOptions_NewLinesForBracesInProperties", // public option deserialized via CSharpVisualStudioOptionStorageReadFallbacks + "CSharpFormattingOptions_NewLinesForBracesInTypes", // public option deserialized via CSharpVisualStudioOptionStorageReadFallbacks + "CSharpFormattingOptions_SpaceWithinCastParentheses", // public option deserialized via CSharpVisualStudioOptionStorageReadFallbacks + "CSharpFormattingOptions_SpaceWithinExpressionParentheses", // public option deserialized via CSharpVisualStudioOptionStorageReadFallbacks + "CSharpFormattingOptions_SpaceWithinOtherParentheses", // public option deserialized via CSharpVisualStudioOptionStorageReadFallbacks + "dotnet_style_operator_placement_when_wrapping", // TODO: https://github.com/dotnet/roslyn/issues/66062 + "dotnet_style_prefer_foreach_explicit_cast_in_source", // For a small customer segment, doesn't warrant VS UI. + "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 + "FeatureOnOffOptions_RenameTracking", // TODO: remove? https://github.com/dotnet/roslyn/issues/66063 + "file_header_template", // repository specific + "FormattingOptions_WrappingColumn", // TODO: https://github.com/dotnet/roslyn/issues/66062 + "InlineHintsOptions_DisplayAllOverride", // TODO: https://github.com/dotnet/roslyn/issues/57283 + "insert_final_newline", // TODO: https://github.com/dotnet/roslyn/issues/66062 + "InternalDiagnosticsOptions_LiveShareDiagnosticMode", // TODO: remove once switched to LSP diagnostics + "InternalDiagnosticsOptions_RazorDiagnosticMode", // TODO: remove once switched to LSP diagnostics + "RazorDesignTimeDocumentFormattingOptions_TabSize", // TODO: remove once Razor removes design-time documents + "RazorDesignTimeDocumentFormattingOptions_UseTabs", // TODO: remove once Razor removes design-time documents + "RecommendationOptions_FilterOutOfScopeLocals", // public option not stored in VS storage + "RecommendationOptions_HideAdvancedMembers", // public option not stored in VS storage + "RenameOptions_PreviewChanges", // public option, deprecated + "RenameOptions_RenameInComments", // public option, deprecated + "RenameOptions_RenameInStrings", // public option, deprecated + "RenameOptions_RenameOverloads", // public option, deprecated + "SimplificationOptions_AllowSimplificationToBaseType", // public option, deprecated + "SimplificationOptions_AllowSimplificationToGenericType", // public option, deprecated + "SimplificationOptions_PreferAliasToQualification", // public option, deprecated + "SimplificationOptions_PreferImplicitTypeInference", // public option, deprecated + "SimplificationOptions_PreferImplicitTypeInLocalDeclaration", // public option, deprecated + "SimplificationOptions_PreferIntrinsicPredefinedTypeKeywordInDeclaration", // public option, deprecated + "SimplificationOptions_PreferIntrinsicPredefinedTypeKeywordInMemberAccess", // public option, deprecated + "SimplificationOptions_PreferOmittingModuleNamesInQualification", // public option, deprecated + "SimplificationOptions_QualifyEventAccess", // public option, deprecated + "SimplificationOptions_QualifyFieldAccess", // public option, deprecated + "SimplificationOptions_QualifyMemberAccessWithThisOrMe", // public option, deprecated + "SimplificationOptions_QualifyMethodAccess", // public option, deprecated + "SimplificationOptions_QualifyPropertyAccess", // public option, deprecated + "SolutionCrawlerOptionsStorage_SolutionBackgroundAnalysisScopeOption", // handled by PackageSettingsPersister + }, optionsWithoutStorage); + } +} diff --git a/src/VisualStudio/Core/Test.Next/Services/SolutionServiceTests.cs b/src/VisualStudio/Core/Test.Next/Services/SolutionServiceTests.cs index c26a06654968a..bb2e268295649 100644 --- a/src/VisualStudio/Core/Test.Next/Services/SolutionServiceTests.cs +++ b/src/VisualStudio/Core/Test.Next/Services/SolutionServiceTests.cs @@ -469,8 +469,8 @@ public async Task TestAddingProjectsWithExplicitOptions(bool useDefaultOptionVal ? FormattingOptions2.NewLine.DefaultValue : FormattingOptions2.NewLine.DefaultValue + FormattingOptions2.NewLine.DefaultValue; solution = solution.WithOptions(solution.Options - .WithChangedOption(FormattingOptions2.NewLine, LanguageNames.CSharp, newOptionValue) - .WithChangedOption(FormattingOptions2.NewLine, LanguageNames.VisualBasic, newOptionValue)); + .WithChangedOption(FormattingOptions.NewLine, LanguageNames.CSharp, newOptionValue) + .WithChangedOption(FormattingOptions.NewLine, LanguageNames.VisualBasic, newOptionValue)); assetProvider = await GetAssetProviderAsync(workspace, remoteWorkspace, solution); solutionChecksum = await solution.State.GetChecksumAsync(CancellationToken.None); diff --git a/src/VisualStudio/Core/Test.Next/Services/VisualStudioDiagnosticAnalyzerExecutorTests.cs b/src/VisualStudio/Core/Test.Next/Services/VisualStudioDiagnosticAnalyzerExecutorTests.cs index a783aa82f028f..2d911c0de6015 100644 --- a/src/VisualStudio/Core/Test.Next/Services/VisualStudioDiagnosticAnalyzerExecutorTests.cs +++ b/src/VisualStudio/Core/Test.Next/Services/VisualStudioDiagnosticAnalyzerExecutorTests.cs @@ -183,7 +183,7 @@ void Method() workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences(new[] { analyzerReference })); var ideAnalyzerOptions = IdeAnalyzerOptions.GetDefault(workspace.Services.SolutionServices.GetLanguageServices(LanguageNames.CSharp)); - workspace.GlobalOptions.SetGlobalOption(new OptionKey(CSharpCodeStyleOptions.VarWhenTypeIsApparent), new CodeStyleOption(false, NotificationOption.Suggestion)); + workspace.GlobalOptions.SetGlobalOption(CSharpCodeStyleOptions.VarWhenTypeIsApparent, new CodeStyleOption(false, NotificationOption.Suggestion)); // run analysis var project = workspace.CurrentSolution.Projects.First(); @@ -274,8 +274,8 @@ private static TestWorkspace CreateWorkspace(string language, string code, Parse ? TestWorkspace.CreateCSharp(code, parseOptions: options, composition: composition) : TestWorkspace.CreateVisualBasic(code, parseOptions: options, composition: composition); - workspace.GlobalOptions.SetGlobalOption(new OptionKey(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp), BackgroundAnalysisScope.FullSolution); - workspace.GlobalOptions.SetGlobalOption(new OptionKey(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.VisualBasic), BackgroundAnalysisScope.FullSolution); + workspace.GlobalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp, BackgroundAnalysisScope.FullSolution); + workspace.GlobalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.VisualBasic, BackgroundAnalysisScope.FullSolution); return workspace; } diff --git a/src/VisualStudio/Core/Test/Completion/CSharpCompletionSnippetNoteTests.vb b/src/VisualStudio/Core/Test/Completion/CSharpCompletionSnippetNoteTests.vb index e74a25fd3ce79..f76ed6b65c526 100644 --- a/src/VisualStudio/Core/Test/Completion/CSharpCompletionSnippetNoteTests.vb +++ b/src/VisualStudio/Core/Test/Completion/CSharpCompletionSnippetNoteTests.vb @@ -119,7 +119,7 @@ class C Dim testSnippetInfoService = DirectCast(state.Workspace.Services.GetLanguageServices(LanguageNames.CSharp).GetService(Of ISnippetInfoService)(), TestCSharpSnippetInfoService) testSnippetInfoService.SetSnippetShortcuts({"for"}) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(InternalFeatureOnOffOptions.Snippets), False) + state.Workspace.GlobalOptions.SetGlobalOption(InternalFeatureOnOffOptions.Snippets, False) state.SendTypeChars("for") Await state.AssertCompletionSession() @@ -136,7 +136,7 @@ class C Dim testSnippetInfoService = DirectCast(state.Workspace.Services.GetLanguageServices(LanguageNames.CSharp).GetService(Of ISnippetInfoService)(), TestCSharpSnippetInfoService) testSnippetInfoService.SetSnippetShortcuts(snippetShortcuts) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowNewSnippetExperienceUserOption, LanguageNames.CSharp), False) + state.Workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ShowNewSnippetExperienceUserOption, LanguageNames.CSharp, False) Return state End Function End Class diff --git a/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb b/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb index 6ae8da303b8d5..0e360711c1322 100644 --- a/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb +++ b/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb @@ -362,7 +362,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics Public Async Function TestExternalDiagnostics_CompilationAnalyzerWithFSAOn() As Task Using workspace = TestWorkspace.CreateCSharp(String.Empty, composition:=s_compositionWithMockDiagnosticUpdateSourceRegistrationService) ' turn on FSA - workspace.GlobalOptions.SetGlobalOption(New OptionKey(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp), BackgroundAnalysisScope.FullSolution) + workspace.GlobalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp, BackgroundAnalysisScope.FullSolution) Dim analyzer = New CompilationAnalyzer() Dim compiler = DiagnosticExtensions.GetCompilerDiagnosticAnalyzer(LanguageNames.CSharp) diff --git a/src/VisualStudio/Core/Test/Options/BasicEditorConfigGeneratorTests.vb b/src/VisualStudio/Core/Test/Options/BasicEditorConfigGeneratorTests.vb index 9afcdf922acb1..53c433d36c7d3 100644 --- a/src/VisualStudio/Core/Test/Options/BasicEditorConfigGeneratorTests.vb +++ b/src/VisualStudio/Core/Test/Options/BasicEditorConfigGeneratorTests.vb @@ -8,6 +8,7 @@ Imports Microsoft.CodeAnalysis.CodeStyle Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Test.Utilities +Imports Microsoft.VisualStudio.LanguageServices.Implementation.Options Imports Roslyn.Test.Utilities Namespace Microsoft.VisualStudio.LanguageServices.UnitTests @@ -147,7 +148,8 @@ dotnet_naming_style.begins_with_i.word_separator = dotnet_naming_style.begins_with_i.capitalization = pascal_case " Dim editorConfigOptions = VisualBasic.Options.Formatting.CodeStylePage.TestAccessor.GetEditorConfigOptions() - Dim actualText = EditorConfigFileGenerator.Generate(editorConfigOptions, workspace.Options, LanguageNames.VisualBasic) + Dim options = New OptionStore(workspace.GlobalOptions) + Dim actualText = EditorConfigFileGenerator.Generate(editorConfigOptions, options, LanguageNames.VisualBasic) AssertEx.EqualOrDiff(expectedText, actualText) End Using End Sub @@ -155,8 +157,8 @@ dotnet_naming_style.begins_with_i.capitalization = pascal_case Public Sub TestEditorConfigGeneratorToggleOptions() Using workspace = TestWorkspace.CreateVisualBasic("") - Dim changedOptions = workspace.Options.WithChangedOption(New OptionKey2(CodeStyleOptions2.PreferExplicitTupleNames, LanguageNames.VisualBasic), - New CodeStyleOption2(Of Boolean)(False, NotificationOption2.[Error])) + Dim options = New OptionStore(workspace.GlobalOptions) + options.SetOption(CodeStyleOptions2.PreferExplicitTupleNames, LanguageNames.VisualBasic, New CodeStyleOption2(Of Boolean)(False, NotificationOption2.[Error])) Dim expectedText = "# Remove the line below if you want to inherit .editorconfig settings from higher directories root = true @@ -286,7 +288,7 @@ dotnet_naming_style.begins_with_i.word_separator = dotnet_naming_style.begins_with_i.capitalization = pascal_case " Dim editorConfigOptions = VisualBasic.Options.Formatting.CodeStylePage.TestAccessor.GetEditorConfigOptions() - Dim actualText = EditorConfigFileGenerator.Generate(editorConfigOptions, changedOptions, LanguageNames.VisualBasic) + Dim actualText = EditorConfigFileGenerator.Generate(editorConfigOptions, options, LanguageNames.VisualBasic) AssertEx.EqualOrDiff(expectedText, actualText) End Using End Sub diff --git a/src/VisualStudio/Core/Test/Options/CSharpEditorConfigGeneratorTests.vb b/src/VisualStudio/Core/Test/Options/CSharpEditorConfigGeneratorTests.vb index 05f4d30c33fea..23ee2bec43c51 100644 --- a/src/VisualStudio/Core/Test/Options/CSharpEditorConfigGeneratorTests.vb +++ b/src/VisualStudio/Core/Test/Options/CSharpEditorConfigGeneratorTests.vb @@ -7,6 +7,7 @@ Imports Microsoft.CodeAnalysis.CodeStyle Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Test.Utilities +Imports Microsoft.VisualStudio.LanguageServices.Implementation.Options Imports Roslyn.Test.Utilities Namespace Microsoft.VisualStudio.LanguageServices.UnitTests @@ -247,7 +248,8 @@ dotnet_naming_style.begins_with_i.word_separator = dotnet_naming_style.begins_with_i.capitalization = pascal_case " Dim editorConfigOptions = CSharp.Options.Formatting.CodeStylePage.TestAccessor.GetEditorConfigOptions() - Dim actualText = EditorConfigFileGenerator.Generate(editorConfigOptions, workspace.Options, LanguageNames.CSharp) + Dim options = New OptionStore(workspace.GlobalOptions) + Dim actualText = EditorConfigFileGenerator.Generate(editorConfigOptions, options, LanguageNames.CSharp) AssertEx.EqualOrDiff(expectedText, actualText) End Using End Sub @@ -255,8 +257,9 @@ dotnet_naming_style.begins_with_i.capitalization = pascal_case Public Sub TestEditorConfigGeneratorToggleOptions() Using workspace = TestWorkspace.CreateCSharp("") - Dim changedOptions = workspace.Options.WithChangedOption(New OptionKey2(CodeStyleOptions2.PreferExplicitTupleNames, LanguageNames.CSharp), - New CodeStyleOption2(Of Boolean)(False, NotificationOption2.[Error])) + Dim options = New OptionStore(workspace.GlobalOptions) + options.SetOption(CodeStyleOptions2.PreferExplicitTupleNames, LanguageNames.CSharp, New CodeStyleOption2(Of Boolean)(False, NotificationOption2.[Error])) + Dim expectedText = "# Remove the line below if you want to inherit .editorconfig settings from higher directories root = true @@ -487,7 +490,7 @@ dotnet_naming_style.begins_with_i.word_separator = dotnet_naming_style.begins_with_i.capitalization = pascal_case " Dim editorConfigOptions = CSharp.Options.Formatting.CodeStylePage.TestAccessor.GetEditorConfigOptions() - Dim actualText = EditorConfigFileGenerator.Generate(editorConfigOptions, changedOptions, LanguageNames.CSharp) + Dim actualText = EditorConfigFileGenerator.Generate(editorConfigOptions, options, LanguageNames.CSharp) AssertEx.EqualOrDiff(expectedText, actualText) End Using End Sub diff --git a/src/VisualStudio/Core/Test/ProjectSystemShim/VisualBasicCompilerOptionsTests.vb b/src/VisualStudio/Core/Test/ProjectSystemShim/VisualBasicCompilerOptionsTests.vb index d5d79081d415c..72a6637cb94aa 100644 --- a/src/VisualStudio/Core/Test/ProjectSystemShim/VisualBasicCompilerOptionsTests.vb +++ b/src/VisualStudio/Core/Test/ProjectSystemShim/VisualBasicCompilerOptionsTests.vb @@ -212,7 +212,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim project.SetCompilerOptions(compilerOptions) Assert.Equal("C:\test.dll", project.GetOutputFileName()) - Assert.Equal("C:\test.dll", project.Test_VisualStudioProject.CompilationOutputAssemblyFilePath) + Assert.Equal("C:\test.dll", project.Test_ProjectSystemProject.CompilationOutputAssemblyFilePath) ' Change output folder from command line arguments - verify that objOutputPath changes. Dim newPath = "C:\NewFolder\test.dll" @@ -222,7 +222,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim project.SetCompilerOptions(compilerOptions) Assert.Equal(newPath, project.GetOutputFileName()) - Assert.Equal("C:\NewFolder\test.dll", project.Test_VisualStudioProject.CompilationOutputAssemblyFilePath) + Assert.Equal("C:\NewFolder\test.dll", project.Test_ProjectSystemProject.CompilationOutputAssemblyFilePath) ' Change output file name - verify that outputPath changes. newPath = "C:\NewFolder\test2.dll" @@ -232,7 +232,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim project.SetCompilerOptions(compilerOptions) Assert.Equal(newPath, project.GetOutputFileName()) - Assert.Equal("C:\NewFolder\test2.dll", project.Test_VisualStudioProject.CompilationOutputAssemblyFilePath) + Assert.Equal("C:\NewFolder\test2.dll", project.Test_ProjectSystemProject.CompilationOutputAssemblyFilePath) ' Change output file name and folder - verify that outputPath changes. newPath = "C:\NewFolder3\test3.dll" @@ -242,7 +242,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim project.SetCompilerOptions(compilerOptions) Assert.Equal(newPath, project.GetOutputFileName()) - Assert.Equal("C:\NewFolder3\test3.dll", project.Test_VisualStudioProject.CompilationOutputAssemblyFilePath) + Assert.Equal("C:\NewFolder3\test3.dll", project.Test_ProjectSystemProject.CompilationOutputAssemblyFilePath) ' Relative path - set by VBIntelliProj in VB Web App project compilerOptions = CreateMinimalCompilerOptions(project) @@ -250,7 +250,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim compilerOptions.wszExeName = "test3.dll" project.SetCompilerOptions(compilerOptions) Assert.Equal(Nothing, project.GetOutputFileName()) - Assert.Equal(Nothing, project.Test_VisualStudioProject.CompilationOutputAssemblyFilePath) + Assert.Equal(Nothing, project.Test_ProjectSystemProject.CompilationOutputAssemblyFilePath) End Using End Sub End Class diff --git a/src/VisualStudio/Core/Test/ProjectSystemShim/VisualStudioAnalyzerTests.vb b/src/VisualStudio/Core/Test/ProjectSystemShim/VisualStudioAnalyzerTests.vb index 49a6613bca16f..5a705c1da70df 100644 --- a/src/VisualStudio/Core/Test/ProjectSystemShim/VisualStudioAnalyzerTests.vb +++ b/src/VisualStudio/Core/Test/ProjectSystemShim/VisualStudioAnalyzerTests.vb @@ -11,6 +11,7 @@ Imports Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Test.Utilities +Imports Microsoft.CodeAnalysis.Workspaces.ProjectSystem Imports Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem Imports Microsoft.VisualStudio.LanguageServices.Implementation.TaskList Imports Roslyn.Test.Utilities @@ -34,7 +35,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim Dim registrationService = Assert.IsType(Of MockDiagnosticUpdateSourceRegistrationService)(workspace.GetService(Of IDiagnosticUpdateSourceRegistrationService)()) Dim hostDiagnosticUpdateSource = New HostDiagnosticUpdateSource(lazyWorkspace, registrationService) - Using tempRoot = New TempRoot(), analyzer = New VisualStudioAnalyzer(tempRoot.CreateFile().Path, hostDiagnosticUpdateSource, ProjectId.CreateNewId(), LanguageNames.VisualBasic) + Using tempRoot = New TempRoot(), analyzer = New ProjectAnalyzerReference(tempRoot.CreateFile().Path, hostDiagnosticUpdateSource, ProjectId.CreateNewId(), LanguageNames.VisualBasic) Dim reference1 = analyzer.GetReference() Dim reference2 = analyzer.GetReference() @@ -59,7 +60,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim Dim eventHandler = New EventHandlers(file) AddHandler hostDiagnosticUpdateSource.DiagnosticsUpdated, AddressOf eventHandler.DiagnosticAddedTest - Using analyzer = New VisualStudioAnalyzer(file, hostDiagnosticUpdateSource, ProjectId.CreateNewId(), LanguageNames.VisualBasic) + Using analyzer = New ProjectAnalyzerReference(file, hostDiagnosticUpdateSource, ProjectId.CreateNewId(), LanguageNames.VisualBasic) Dim reference = analyzer.GetReference() reference.GetAnalyzers(LanguageNames.VisualBasic) diff --git a/src/VisualStudio/Core/Test/Snippets/SnippetCompletionProviderTests.vb b/src/VisualStudio/Core/Test/Snippets/SnippetCompletionProviderTests.vb index 46f5f9a8353f3..75ea24690f3b7 100644 --- a/src/VisualStudio/Core/Test/Snippets/SnippetCompletionProviderTests.vb +++ b/src/VisualStudio/Core/Test/Snippets/SnippetCompletionProviderTests.vb @@ -83,7 +83,7 @@ End Class.Value Dim testState = SnippetTestState.CreateTestState(markup, LanguageNames.VisualBasic, extraParts:={GetType(MockSnippetInfoService)}) Using testState Dim workspace = testState.Workspace - workspace.GlobalOptions.SetGlobalOption(New Options.OptionKey(CompletionOptionsStorage.SnippetsBehavior, LanguageNames.VisualBasic), SnippetsRule.AlwaysInclude) + workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.SnippetsBehavior, LanguageNames.VisualBasic, SnippetsRule.AlwaysInclude) testState.SendTypeChars("'T") Await testState.AssertNoCompletionSession() End Using @@ -100,7 +100,7 @@ End Class.Value Dim testState = SnippetTestState.CreateTestState(markup, LanguageNames.VisualBasic, extraParts:={GetType(MockSnippetInfoService)}) Using testState Dim workspace = testState.Workspace - workspace.GlobalOptions.SetGlobalOption(New Options.OptionKey(CompletionOptionsStorage.SnippetsBehavior, LanguageNames.VisualBasic), SnippetsRule.AlwaysInclude) + workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.SnippetsBehavior, LanguageNames.VisualBasic, SnippetsRule.AlwaysInclude) testState.SendTypeChars("'''T") Await testState.AssertNoCompletionSession() End Using @@ -116,7 +116,7 @@ End Class.Value Dim testState = SnippetTestState.CreateTestState(markup, LanguageNames.VisualBasic, extraParts:={GetType(MockSnippetInfoService)}) Using testState Dim workspace = testState.Workspace - workspace.GlobalOptions.SetGlobalOption(New Options.OptionKey(CompletionOptionsStorage.SnippetsBehavior, LanguageNames.VisualBasic), SnippetsRule.AlwaysInclude) + workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.SnippetsBehavior, LanguageNames.VisualBasic, SnippetsRule.AlwaysInclude) testState.SendTypeChars("Shortcut") Await testState.AssertSelectedCompletionItem(displayText:="Shortcut") End Using diff --git a/src/VisualStudio/Core/Test/Snippets/SnippetTestState.vb b/src/VisualStudio/Core/Test/Snippets/SnippetTestState.vb index b94fc5cfead78..0d9233e5bde4e 100644 --- a/src/VisualStudio/Core/Test/Snippets/SnippetTestState.vb +++ b/src/VisualStudio/Core/Test/Snippets/SnippetTestState.vb @@ -42,7 +42,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Snippets excludedTypes:={GetType(IIntelliSensePresenter(Of ISignatureHelpPresenterSession, ISignatureHelpSession)), GetType(FormatCommandHandler)}.Concat(If(excludedTypes, {})).ToList(), includeFormatCommandHandler:=False) - Workspace.GlobalOptions.SetGlobalOption(New OptionKey(InternalFeatureOnOffOptions.Snippets), True) + Workspace.GlobalOptions.SetGlobalOption(InternalFeatureOnOffOptions.Snippets, True) Dim mockSVsServiceProvider = New Mock(Of SVsServiceProvider)(MockBehavior.Strict) mockSVsServiceProvider.Setup(Function(s) s.GetService(GetType(SVsTextManager))).Returns(Nothing) @@ -103,7 +103,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Snippets Dim state = New SnippetTestState(workspaceXml, languageName, startActiveSession, extraParts, excludedTypes:=Enumerable.Empty(Of Type), WorkspaceKind.Interactive) - state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(InternalFeatureOnOffOptions.Snippets), False) + state.Workspace.GlobalOptions.SetGlobalOption(InternalFeatureOnOffOptions.Snippets, False) Return state End Function diff --git a/src/VisualStudio/Core/Test/TaskList/TaskListTableDataSourceTests.vb b/src/VisualStudio/Core/Test/TaskList/TaskListTableDataSourceTests.vb index f739405bb4fa9..7b1878112c2cb 100644 --- a/src/VisualStudio/Core/Test/TaskList/TaskListTableDataSourceTests.vb +++ b/src/VisualStudio/Core/Test/TaskList/TaskListTableDataSourceTests.vb @@ -248,8 +248,8 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.TaskList Dim span2 = New FileLinePositionSpan("test2", pos, pos) Dim span1 = New FileLinePositionSpan("test1", pos, pos) provider.Items = New TaskListItem() { - New TaskListItem(priority:=1, message:="test2", documentId:=documentId, span:=span2, mappedSpan:=span2), - New TaskListItem(priority:=0, message:="test", documentId:=documentId, span:=span1, mappedSpan:=span1) + New TaskListItem(Priority:=TaskListItemPriority.Medium, Message:="test2", DocumentId:=documentId, Span:=span2, MappedSpan:=span2), + New TaskListItem(Priority:=TaskListItemPriority.Low, Message:="test", DocumentId:=documentId, Span:=span1, MappedSpan:=span1) } provider.RaiseTodoListUpdated(workspace) @@ -286,8 +286,8 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.TaskList Dim span2 = New FileLinePositionSpan("test2", pos, pos) Dim span3 = New FileLinePositionSpan("test3", pos, pos) provider.Items = New TaskListItem() { - New TaskListItem(priority:=1, message:="test2", documentId:=documentId, span:=span2, mappedSpan:=span2), - New TaskListItem(priority:=0, message:="test3", documentId:=documentId, span:=span3, mappedSpan:=span3) + New TaskListItem(Priority:=TaskListItemPriority.Medium, Message:="test2", DocumentId:=documentId, Span:=span2, MappedSpan:=span2), + New TaskListItem(Priority:=TaskListItemPriority.Low, Message:="test3", DocumentId:=documentId, Span:=span3, MappedSpan:=span3) } provider.RaiseTodoListUpdated(workspace) diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpAddMissingUsingsOnPaste.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpAddMissingUsingsOnPaste.cs index b5a43beff355b..16a047fbacb8d 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpAddMissingUsingsOnPaste.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpAddMissingUsingsOnPaste.cs @@ -50,7 +50,7 @@ static void Main(string[] args) }", HangMitigatingCancellationToken); var globalOptions = await TestServices.Shell.GetComponentModelServiceAsync(HangMitigatingCancellationToken); - globalOptions.SetGlobalOption(new OptionKey(FeatureOnOffOptions.AddImportsOnPaste, LanguageNames.CSharp), false); + globalOptions.SetGlobalOption(FeatureOnOffOptions.AddImportsOnPaste, LanguageNames.CSharp, false); await PasteAsync(@"Task DoThingAsync() => Task.CompletedTask;", HangMitigatingCancellationToken); @@ -98,7 +98,7 @@ static void Main(string[] args) await using var telemetry = await TestServices.Telemetry.EnableTestTelemetryChannelAsync(HangMitigatingCancellationToken); var globalOptions = await TestServices.Shell.GetComponentModelServiceAsync(HangMitigatingCancellationToken); - globalOptions.SetGlobalOption(new OptionKey(FeatureOnOffOptions.AddImportsOnPaste, LanguageNames.CSharp), true); + globalOptions.SetGlobalOption(FeatureOnOffOptions.AddImportsOnPaste, LanguageNames.CSharp, true); await PasteAsync(@"Task DoThingAsync() => Task.CompletedTask;", HangMitigatingCancellationToken); @@ -145,7 +145,7 @@ static void Main(string[] args) }", HangMitigatingCancellationToken); var globalOptions = await TestServices.Shell.GetComponentModelServiceAsync(HangMitigatingCancellationToken); - globalOptions.SetGlobalOption(new OptionKey(FeatureOnOffOptions.AddImportsOnPaste, LanguageNames.CSharp), true); + globalOptions.SetGlobalOption(FeatureOnOffOptions.AddImportsOnPaste, LanguageNames.CSharp, true); await PasteAsync(@"Task DoThingAsync() => Task.CompletedTask;", HangMitigatingCancellationToken); diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpArgumentProvider.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpArgumentProvider.cs index dd6cda2d72026..22a836ac4c687 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpArgumentProvider.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpArgumentProvider.cs @@ -29,8 +29,8 @@ public override async Task InitializeAsync() await base.InitializeAsync().ConfigureAwait(true); var globalOptions = await TestServices.Shell.GetComponentModelServiceAsync(HangMitigatingCancellationToken); - globalOptions.SetGlobalOption(new OptionKey(CompletionViewOptions.EnableArgumentCompletionSnippets, LanguageNames.CSharp), true); - globalOptions.SetGlobalOption(new OptionKey(CompletionViewOptions.EnableArgumentCompletionSnippets, LanguageNames.VisualBasic), true); + globalOptions.SetGlobalOption(CompletionViewOptions.EnableArgumentCompletionSnippets, LanguageNames.CSharp, true); + globalOptions.SetGlobalOption(CompletionViewOptions.EnableArgumentCompletionSnippets, LanguageNames.VisualBasic, true); } [IdeFact] diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpGoToDefinition.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpGoToDefinition.cs index 5450cc1fe636f..181ac950c2402 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpGoToDefinition.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpGoToDefinition.cs @@ -111,7 +111,7 @@ partial class PartialClass { int i = 0; }", HangMitigatingCancellationToken); public async Task GoToDefinitionFromMetadataCollapsed() { var globalOptions = await TestServices.Shell.GetComponentModelServiceAsync(HangMitigatingCancellationToken); - globalOptions.SetGlobalOption(new OptionKey(BlockStructureOptionsStorage.CollapseSourceLinkEmbeddedDecompiledFilesWhenFirstOpened, language: LanguageName), true); + globalOptions.SetGlobalOption(BlockStructureOptionsStorage.CollapseSourceLinkEmbeddedDecompiledFilesWhenFirstOpened, language: LanguageName, true); await TestServices.SolutionExplorer.AddFileAsync(ProjectName, "C.cs", cancellationToken: HangMitigatingCancellationToken); await TestServices.SolutionExplorer.OpenFileAsync(ProjectName, "C.cs", HangMitigatingCancellationToken); @@ -142,7 +142,7 @@ public async Task GoToDefinitionFromMetadataNotCollapsed() { var globalOptions = await TestServices.Shell.GetComponentModelServiceAsync(HangMitigatingCancellationToken); - globalOptions.SetGlobalOption(new OptionKey(BlockStructureOptionsStorage.CollapseSourceLinkEmbeddedDecompiledFilesWhenFirstOpened, language: LanguageName), false); + globalOptions.SetGlobalOption(BlockStructureOptionsStorage.CollapseSourceLinkEmbeddedDecompiledFilesWhenFirstOpened, language: LanguageName, false); await TestServices.SolutionExplorer.AddFileAsync(ProjectName, "C.cs", cancellationToken: HangMitigatingCancellationToken); await TestServices.SolutionExplorer.OpenFileAsync(ProjectName, "C.cs", HangMitigatingCancellationToken); diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpNavigationBar.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpNavigationBar.cs index 2bc6205268b82..28a8c45b932aa 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpNavigationBar.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpNavigationBar.cs @@ -128,10 +128,10 @@ void Bar() { } public async Task VerifyOption() { var globalOptions = await TestServices.Shell.GetComponentModelServiceAsync(HangMitigatingCancellationToken); - globalOptions.SetGlobalOption(new OptionKey(NavigationBarViewOptionsStorage.ShowNavigationBar, LanguageNames.CSharp), false); + globalOptions.SetGlobalOption(NavigationBarViewOptionsStorage.ShowNavigationBar, LanguageNames.CSharp, false); Assert.False(await TestServices.Editor.IsNavigationBarEnabledAsync(HangMitigatingCancellationToken)); - globalOptions.SetGlobalOption(new OptionKey(NavigationBarViewOptionsStorage.ShowNavigationBar, LanguageNames.CSharp), true); + globalOptions.SetGlobalOption(NavigationBarViewOptionsStorage.ShowNavigationBar, LanguageNames.CSharp, true); Assert.True(await TestServices.Editor.IsNavigationBarEnabledAsync(HangMitigatingCancellationToken)); } } diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpSourceGenerators.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpSourceGenerators.cs index 2393ee22354cb..d8d5430912df5 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpSourceGenerators.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpSourceGenerators.cs @@ -86,7 +86,7 @@ public static void Main() configurationService.Clear(); var globalOptions = await TestServices.Shell.GetComponentModelServiceAsync(HangMitigatingCancellationToken); - globalOptions.SetGlobalOption(new OptionKey(WorkspaceConfigurationOptionsStorage.EnableOpeningSourceGeneratedFilesInWorkspace, language: null), true); + globalOptions.SetGlobalOption(WorkspaceConfigurationOptionsStorage.EnableOpeningSourceGeneratedFilesInWorkspace, true); await TestServices.Editor.GoToDefinitionAsync(HangMitigatingCancellationToken); Assert.Equal($"{HelloWorldGenerator.GeneratedEnglishClassName}.cs {ServicesVSResources.generated_suffix}", await TestServices.Shell.GetActiveWindowCaptionAsync(HangMitigatingCancellationToken)); diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/InheritanceMarginInProcess.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/InheritanceMarginInProcess.cs index db6846d5f38d8..46d9ceb2302bf 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/InheritanceMarginInProcess.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/InheritanceMarginInProcess.cs @@ -33,18 +33,18 @@ public async Task EnableOptionsAsync(string languageName, CancellationToken canc if (showInheritanceMargin != true) { - optionService.SetGlobalOption(new OptionKey(FeatureOnOffOptions.ShowInheritanceMargin, languageName), true); + optionService.SetGlobalOption(FeatureOnOffOptions.ShowInheritanceMargin, languageName, true); } if (!showGlobalUsings) { - optionService.SetGlobalOption(new OptionKey(FeatureOnOffOptions.InheritanceMarginIncludeGlobalImports, languageName), true); + optionService.SetGlobalOption(FeatureOnOffOptions.InheritanceMarginIncludeGlobalImports, languageName, true); } if (combinedWithIndicatorMargin) { // Glyphs in Indicator margin are owned by editor, and we don't know when the glyphs would be added/removed. - optionService.SetGlobalOption(new OptionKey(FeatureOnOffOptions.InheritanceMarginCombinedWithIndicatorMargin), false); + optionService.SetGlobalOption(FeatureOnOffOptions.InheritanceMarginCombinedWithIndicatorMargin, false); } } @@ -56,12 +56,12 @@ public async Task DisableOptionsAsync(string languageName, CancellationToken can if (showInheritanceMargin != false) { - optionService.SetGlobalOption(new OptionKey(FeatureOnOffOptions.ShowInheritanceMargin, languageName), false); + optionService.SetGlobalOption(FeatureOnOffOptions.ShowInheritanceMargin, languageName, false); } if (showGlobalUsings) { - optionService.SetGlobalOption(new OptionKey(FeatureOnOffOptions.InheritanceMarginIncludeGlobalImports, languageName), false); + optionService.SetGlobalOption(FeatureOnOffOptions.InheritanceMarginIncludeGlobalImports, languageName, false); } } diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/StateResetInProcess.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/StateResetInProcess.cs index 9e746fb0ef35f..9813069e60ada 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/StateResetInProcess.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/StateResetInProcess.cs @@ -53,13 +53,13 @@ public async Task ResetGlobalOptionsAsync(CancellationToken cancellationToken) static void ResetOption(IGlobalOptionService globalOptions, Option2 option) { - globalOptions.SetGlobalOption(new OptionKey(option, language: null), option.DefaultValue); + globalOptions.SetGlobalOption(option, option.DefaultValue); } static void ResetPerLanguageOption(IGlobalOptionService globalOptions, PerLanguageOption2 option) { - globalOptions.SetGlobalOption(new OptionKey(option, LanguageNames.CSharp), option.DefaultValue); - globalOptions.SetGlobalOption(new OptionKey(option, LanguageNames.VisualBasic), option.DefaultValue); + globalOptions.SetGlobalOption(option, LanguageNames.CSharp, option.DefaultValue); + globalOptions.SetGlobalOption(option, LanguageNames.VisualBasic, option.DefaultValue); } } diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/WorkspaceInProcess.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/WorkspaceInProcess.cs index d1183cf1d32d8..c61313cb8abc2 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/WorkspaceInProcess.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/WorkspaceInProcess.cs @@ -64,15 +64,14 @@ public async Task SetPrettyListingAsync(string languageName, bool value, Cancell await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); var globalOptions = await GetComponentModelServiceAsync(cancellationToken); - globalOptions.SetGlobalOption(new OptionKey(FeatureOnOffOptions.PrettyListing, languageName), value); + globalOptions.SetGlobalOption(FeatureOnOffOptions.PrettyListing, languageName, value); } public async Task SetFileScopedNamespaceAsync(bool value, CancellationToken cancellationToken) { await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); var globalOptions = await TestServices.Shell.GetComponentModelServiceAsync(cancellationToken); - globalOptions.SetGlobalOption( - new OptionKey(Microsoft.CodeAnalysis.CSharp.CodeStyle.CSharpCodeStyleOptions.NamespaceDeclarations), + globalOptions.SetGlobalOption(Microsoft.CodeAnalysis.CSharp.CodeStyle.CSharpCodeStyleOptions.NamespaceDeclarations, new CodeStyleOption2(value ? NamespaceDeclarationPreference.FileScoped : NamespaceDeclarationPreference.BlockScoped, NotificationOption2.Suggestion)); } @@ -82,12 +81,12 @@ public async Task SetFullSolutionAnalysisAsync(bool value, CancellationToken can var globalOptions = await TestServices.Shell.GetComponentModelServiceAsync(cancellationToken); var scope = value ? BackgroundAnalysisScope.FullSolution : BackgroundAnalysisScope.Default; - globalOptions.SetGlobalOption(new OptionKey(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp), scope); - globalOptions.SetGlobalOption(new OptionKey(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.VisualBasic), scope); + globalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp, scope); + globalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.VisualBasic, scope); var compilerScope = value ? CompilerDiagnosticsScope.FullSolution : CompilerDiagnosticsScope.OpenFiles; - globalOptions.SetGlobalOption(new OptionKey(SolutionCrawlerOptionsStorage.CompilerDiagnosticsScopeOption, LanguageNames.CSharp), compilerScope); - globalOptions.SetGlobalOption(new OptionKey(SolutionCrawlerOptionsStorage.CompilerDiagnosticsScopeOption, LanguageNames.VisualBasic), compilerScope); + globalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.CompilerDiagnosticsScopeOption, LanguageNames.CSharp, compilerScope); + globalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.CompilerDiagnosticsScopeOption, LanguageNames.VisualBasic, compilerScope); } public Task WaitForAsyncOperationsAsync(string featuresToWaitFor, CancellationToken cancellationToken) diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/Microsoft.VisualStudio.LanguageServices.New.IntegrationTests.csproj b/src/VisualStudio/IntegrationTest/New.IntegrationTests/Microsoft.VisualStudio.LanguageServices.New.IntegrationTests.csproj index 2ee0e8902a2e1..43eb3d7562387 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/Microsoft.VisualStudio.LanguageServices.New.IntegrationTests.csproj +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/Microsoft.VisualStudio.LanguageServices.New.IntegrationTests.csproj @@ -12,7 +12,6 @@ - @@ -44,6 +43,7 @@ + diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/Options/GlobalOptionsTest.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/Options/GlobalOptionsTest.cs new file mode 100644 index 0000000000000..1e270cee0a822 --- /dev/null +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/Options/GlobalOptionsTest.cs @@ -0,0 +1,97 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.TaskList; +using Microsoft.CodeAnalysis.UnitTests; +using Microsoft.VisualStudio.IntegrationTest.Utilities; +using Microsoft.VisualStudio.LanguageServices; +using Microsoft.VisualStudio.LanguageServices.Options; +using Microsoft.VisualStudio.Settings; +using Roslyn.Test.Utilities; +using Roslyn.Utilities; +using Roslyn.VisualStudio.IntegrationTests; +using Xunit; + +namespace Roslyn.VisualStudio.NewIntegrationTests.Options; + +public sealed class GlobalOptionsTest : AbstractIntegrationTest +{ + public GlobalOptionsTest() + { + } + + [IdeFact] + public async Task ValidateAllOptions() + { + var globalOptions = (GlobalOptionService)await TestServices.Shell.GetComponentModelServiceAsync(HangMitigatingCancellationToken); + var provider = await TestServices.Shell.GetComponentModelServiceAsync(HangMitigatingCancellationToken); + var vsSettingsPersister = (VisualStudioOptionPersister)await provider.GetOrCreatePersisterAsync(HangMitigatingCancellationToken); + + var optionsInfo = OptionsTestInfo.CollectOptions(Path.GetDirectoryName(typeof(GlobalOptionsTest).Assembly.Location!)); + var allLanguages = new[] { LanguageNames.CSharp, LanguageNames.VisualBasic }; + var noLanguages = new[] { (string?)null }; + + foreach (var (configName, optionInfo) in optionsInfo) + { + var option = optionInfo.Option; + + // skip public options: + if (option is IPublicOption) + { + continue; + } + + if (!VisualStudioOptionStorage.Storages.TryGetValue(configName, out var storage)) + { + continue; + } + + // TODO: issue https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1585884 + if (option == TaskListOptionsStorage.Descriptors) + { + continue; + } + + foreach (var language in option.IsPerLanguage ? allLanguages : noLanguages) + { + var key = new OptionKey2(option, language); + var currentValue = globalOptions.GetOption(key); + + // do not attempt to update feature flags + if (storage is VisualStudioOptionStorage.FeatureFlagStorage) + { + Assert.True(currentValue is bool); + continue; + } + + var differentValue = OptionsTestHelpers.GetDifferentValue(option.Type, currentValue); + + await vsSettingsPersister.PersistAsync(storage, key, differentValue); + + // make sure we fetch the value from the storage: + globalOptions.ClearCachedValues(); + + object? updatedValue; + try + { + updatedValue = globalOptions.GetOption(key); + } + finally + { + await vsSettingsPersister.PersistAsync(storage, key, currentValue); + } + + AssertEx.AreEqual(differentValue, updatedValue, message: $"Option '{option.Definition.ConfigName}' failed to persist to VS settings."); + } + } + } +} diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicArgumentProvider.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicArgumentProvider.cs index 6e5e3dea0265f..0afebe77b9e46 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicArgumentProvider.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicArgumentProvider.cs @@ -28,8 +28,8 @@ public override async Task InitializeAsync() await base.InitializeAsync().ConfigureAwait(true); var globalOptions = await TestServices.Shell.GetComponentModelServiceAsync(HangMitigatingCancellationToken); - globalOptions.SetGlobalOption(new OptionKey(CompletionViewOptions.EnableArgumentCompletionSnippets, LanguageNames.CSharp), true); - globalOptions.SetGlobalOption(new OptionKey(CompletionViewOptions.EnableArgumentCompletionSnippets, LanguageNames.VisualBasic), true); + globalOptions.SetGlobalOption(CompletionViewOptions.EnableArgumentCompletionSnippets, LanguageNames.CSharp, true); + globalOptions.SetGlobalOption(CompletionViewOptions.EnableArgumentCompletionSnippets, LanguageNames.VisualBasic, true); } [IdeFact] diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicGoToDefinition.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicGoToDefinition.cs index ffe487f0de7d4..884459c6d047f 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicGoToDefinition.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicGoToDefinition.cs @@ -56,13 +56,13 @@ await SetUpEditorAsync( @"Class C Dim i As Integer$$ End Class", HangMitigatingCancellationToken); - globalOptions.SetGlobalOption(new OptionKey(VisualStudioNavigationOptions.NavigateToObjectBrowser, LanguageNames.VisualBasic), true); + globalOptions.SetGlobalOption(VisualStudioNavigationOptions.NavigateToObjectBrowser, LanguageNames.VisualBasic, true); await TestServices.Editor.GoToDefinitionAsync(HangMitigatingCancellationToken); Assert.Equal("Object Browser", await TestServices.Shell.GetActiveWindowCaptionAsync(HangMitigatingCancellationToken)); - globalOptions.SetGlobalOption(new OptionKey(VisualStudioNavigationOptions.NavigateToObjectBrowser, LanguageNames.VisualBasic), false); - globalOptions.SetGlobalOption(new OptionKey(MetadataAsSourceOptionsStorage.NavigateToDecompiledSources, language: null), false); + globalOptions.SetGlobalOption(VisualStudioNavigationOptions.NavigateToObjectBrowser, LanguageNames.VisualBasic, false); + globalOptions.SetGlobalOption(MetadataAsSourceOptionsStorage.NavigateToDecompiledSources, false); await TestServices.SolutionExplorer.OpenFileAsync(ProjectName, "Class1.vb", HangMitigatingCancellationToken); await TestServices.Editor.GoToDefinitionAsync(HangMitigatingCancellationToken); diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicLineCommit.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicLineCommit.cs index 2abad245e6987..7b1032dbd0a4c 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicLineCommit.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicLineCommit.cs @@ -146,7 +146,7 @@ End Sub public async Task CommitOnFocusLostDoesNotFormatWithPrettyListingOff() { var globalOptions = await TestServices.Shell.GetComponentModelServiceAsync(HangMitigatingCancellationToken); - globalOptions.SetGlobalOption(new OptionKey(FeatureOnOffOptions.PrettyListing, LanguageNames.VisualBasic), false); + globalOptions.SetGlobalOption(FeatureOnOffOptions.PrettyListing, LanguageNames.VisualBasic, false); await TestServices.Editor.SetTextAsync(@"Module M Sub M() diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicNavigationBar.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicNavigationBar.cs index 6b584a5795d36..a9c04f5549a5b 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicNavigationBar.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicNavigationBar.cs @@ -104,10 +104,10 @@ public async Task VerifyOption() { var globalOptions = await TestServices.Shell.GetComponentModelServiceAsync(HangMitigatingCancellationToken); - globalOptions.SetGlobalOption(new OptionKey(NavigationBarViewOptionsStorage.ShowNavigationBar, LanguageNames.VisualBasic), false); + globalOptions.SetGlobalOption(NavigationBarViewOptionsStorage.ShowNavigationBar, LanguageNames.VisualBasic, false); Assert.False(await TestServices.Editor.IsNavigationBarEnabledAsync(HangMitigatingCancellationToken)); - globalOptions.SetGlobalOption(new OptionKey(NavigationBarViewOptionsStorage.ShowNavigationBar, LanguageNames.VisualBasic), true); + globalOptions.SetGlobalOption(NavigationBarViewOptionsStorage.ShowNavigationBar, LanguageNames.VisualBasic, true); Assert.True(await TestServices.Editor.IsNavigationBarEnabledAsync(HangMitigatingCancellationToken)); } diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/VisualStudioWorkspace_InProc.cs b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/VisualStudioWorkspace_InProc.cs index e28a45d8ac2b9..47c55cc3afa7d 100644 --- a/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/VisualStudioWorkspace_InProc.cs +++ b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/VisualStudioWorkspace_InProc.cs @@ -47,11 +47,10 @@ public bool IsPrettyListingOn(string languageName) => _globalOptions.GetOption(FeatureOnOffOptions.PrettyListing, languageName); public void SetPrettyListing(string languageName, bool value) - => InvokeOnUIThread(_ => _globalOptions.SetGlobalOption(new OptionKey(FeatureOnOffOptions.PrettyListing, languageName), value)); + => InvokeOnUIThread(_ => _globalOptions.SetGlobalOption(FeatureOnOffOptions.PrettyListing, languageName, value)); public void SetFileScopedNamespaces(bool value) - => InvokeOnUIThread(_ => _globalOptions.SetGlobalOption( - new OptionKey(Microsoft.CodeAnalysis.CSharp.CodeStyle.CSharpCodeStyleOptions.NamespaceDeclarations), + => InvokeOnUIThread(_ => _globalOptions.SetGlobalOption(Microsoft.CodeAnalysis.CSharp.CodeStyle.CSharpCodeStyleOptions.NamespaceDeclarations, new CodeStyleOption2(value ? NamespaceDeclarationPreference.FileScoped : NamespaceDeclarationPreference.BlockScoped, NotificationOption2.Suggestion))); public void SetGlobalOption(WellKnownGlobalOption option, string? language, object? value) @@ -133,16 +132,16 @@ public void ResetOptions() return; // Local function - void ResetOption(IOption option) + void ResetOption(IOption2 option) { - if (option is IPerLanguageValuedOption) + if (option.IsPerLanguage) { - _globalOptions.SetGlobalOption(new OptionKey(option, LanguageNames.CSharp), option.DefaultValue); - _globalOptions.SetGlobalOption(new OptionKey(option, LanguageNames.VisualBasic), option.DefaultValue); + _globalOptions.SetGlobalOption(new OptionKey2(option, LanguageNames.CSharp), option.DefaultValue); + _globalOptions.SetGlobalOption(new OptionKey2(option, LanguageNames.VisualBasic), option.DefaultValue); } else { - _globalOptions.SetGlobalOption(new OptionKey(option), option.DefaultValue); + _globalOptions.SetGlobalOption(new OptionKey2(option, language: null), option.DefaultValue); } } } diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/WellKnownGlobalOptions.cs b/src/VisualStudio/IntegrationTest/TestUtilities/WellKnownGlobalOptions.cs index 1ff64f52b6c2b..239ebc0865ee7 100644 --- a/src/VisualStudio/IntegrationTest/TestUtilities/WellKnownGlobalOptions.cs +++ b/src/VisualStudio/IntegrationTest/TestUtilities/WellKnownGlobalOptions.cs @@ -17,7 +17,7 @@ namespace Microsoft.VisualStudio.IntegrationTest.Utilities /// /// Options settable by integration tests. /// - /// TODO: Options are currently explicitly listed since is not serializable. + /// TODO: Options are currently explicitly listed since is not serializable. /// https://github.com/dotnet/roslyn/issues/59267 /// public enum WellKnownGlobalOption @@ -38,9 +38,9 @@ public enum WellKnownGlobalOption InlineRenameSessionOptions_UseNewUI, } - public static class WellKnownGlobalOptions + internal static class WellKnownGlobalOptions { - public static IOption GetOption(this WellKnownGlobalOption option) + public static IOption2 GetOption(this WellKnownGlobalOption option) => option switch { WellKnownGlobalOption.CompletionOptions_ShowItemsFromUnimportedNamespaces => CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, @@ -59,7 +59,7 @@ public static IOption GetOption(this WellKnownGlobalOption option) _ => throw ExceptionUtilities.Unreachable() }; - public static OptionKey GetKey(this WellKnownGlobalOption option, string? language) - => new OptionKey(GetOption(option), language); + public static OptionKey2 GetKey(this WellKnownGlobalOption option, string? language) + => new OptionKey2(GetOption(option), language); } } diff --git a/src/VisualStudio/VisualBasic/Impl/LanguageService/VisualBasicLanguageService.vb b/src/VisualStudio/VisualBasic/Impl/LanguageService/VisualBasicLanguageService.vb index 359a52208be30..84cc9edacb87b 100644 --- a/src/VisualStudio/VisualBasic/Impl/LanguageService/VisualBasicLanguageService.vb +++ b/src/VisualStudio/VisualBasic/Impl/LanguageService/VisualBasicLanguageService.vb @@ -5,6 +5,7 @@ Imports System.Runtime.InteropServices Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.Editor +Imports Microsoft.CodeAnalysis.Workspaces.ProjectSystem Imports Microsoft.VisualStudio.LanguageServices.Implementation.DebuggerIntelliSense Imports Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService Imports Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem @@ -73,7 +74,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic Protected Overrides Function CreateContainedLanguage( bufferCoordinator As IVsTextBufferCoordinator, - project As VisualStudioProject, + project As ProjectSystemProject, hierarchy As IVsHierarchy, itemid As UInteger ) As IVsContainedLanguage diff --git a/src/VisualStudio/VisualBasic/Impl/LanguageService/VisualBasicPackage.vb b/src/VisualStudio/VisualBasic/Impl/LanguageService/VisualBasicPackage.vb index 3e4828425875a..17d2ff76026ed 100644 --- a/src/VisualStudio/VisualBasic/Impl/LanguageService/VisualBasicPackage.vb +++ b/src/VisualStudio/VisualBasic/Impl/LanguageService/VisualBasicPackage.vb @@ -6,6 +6,7 @@ Imports System.Runtime.InteropServices Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.ErrorReporting +Imports Microsoft.CodeAnalysis.Options Imports Microsoft.VisualStudio.LanguageServices.Implementation Imports Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService Imports Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem @@ -116,8 +117,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic Protected Overrides Function GetAutomationObject(name As String) As Object If name = "Basic-Specific" Then - Dim workspace = Me.ComponentModel.GetService(Of VisualStudioWorkspace)() - Return New AutomationObject(workspace) + Return New AutomationObject(ComponentModel.GetService(Of ILegacyGlobalOptionService)) End If Return MyBase.GetAutomationObject(name) diff --git a/src/VisualStudio/VisualBasic/Impl/Options/AutomationObject/AutomationObject.vb b/src/VisualStudio/VisualBasic/Impl/Options/AutomationObject/AutomationObject.vb index 4a8e600f65efb..9707be51d9ce8 100644 --- a/src/VisualStudio/VisualBasic/Impl/Options/AutomationObject/AutomationObject.vb +++ b/src/VisualStudio/VisualBasic/Impl/Options/AutomationObject/AutomationObject.vb @@ -12,8 +12,8 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options Partial Public Class AutomationObject Inherits AbstractAutomationObject - Friend Sub New(workspace As Workspace) - MyBase.New(workspace, LanguageNames.VisualBasic) + Friend Sub New(legacyGlobalOptions As ILegacyGlobalOptionService) + MyBase.New(legacyGlobalOptions, LanguageNames.VisualBasic) End Sub Private Overloads Function GetBooleanOption(key As PerLanguageOption2(Of Boolean)) As Boolean diff --git a/src/VisualStudio/VisualBasic/Impl/Options/Formatting/CodeStylePage.vb b/src/VisualStudio/VisualBasic/Impl/Options/Formatting/CodeStylePage.vb index 496560e9f53bb..30d3645dc87f3 100644 --- a/src/VisualStudio/VisualBasic/Impl/Options/Formatting/CodeStylePage.vb +++ b/src/VisualStudio/VisualBasic/Impl/Options/Formatting/CodeStylePage.vb @@ -23,15 +23,15 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options.Formatting LanguageNames.VisualBasic) End Function - Private Shared Function GetEditorConfigOptions() As ImmutableArray(Of (String, ImmutableArray(Of IOption))) - Dim builder = ArrayBuilder(Of (String, ImmutableArray(Of IOption))).GetInstance() + Private Shared Function GetEditorConfigOptions() As ImmutableArray(Of (String, ImmutableArray(Of IOption2))) + Dim builder = ArrayBuilder(Of (String, ImmutableArray(Of IOption2))).GetInstance() builder.AddRange(GridOptionPreviewControl.GetLanguageAgnosticEditorConfigOptions()) - builder.Add((BasicVSResources.VB_Coding_Conventions, VisualBasicCodeStyleOptions.AllOptions.As(Of IOption))) + builder.Add((BasicVSResources.VB_Coding_Conventions, VisualBasicCodeStyleOptions.AllOptions.As(Of IOption2))) Return builder.ToImmutableAndFree() End Function Friend Structure TestAccessor - Friend Shared Function GetEditorConfigOptions() As ImmutableArray(Of (String, ImmutableArray(Of IOption))) + Friend Shared Function GetEditorConfigOptions() As ImmutableArray(Of (String, ImmutableArray(Of IOption2))) Return CodeStylePage.GetEditorConfigOptions() End Function End Structure diff --git a/src/VisualStudio/VisualBasic/Impl/Options/StyleViewModel.vb b/src/VisualStudio/VisualBasic/Impl/Options/StyleViewModel.vb index 0672709bc764b..786b75791274a 100644 --- a/src/VisualStudio/VisualBasic/Impl/Options/StyleViewModel.vb +++ b/src/VisualStudio/VisualBasic/Impl/Options/StyleViewModel.vb @@ -865,25 +865,25 @@ End Class Private Sub AddParenthesesOptions(optionStore As OptionStore) AddParenthesesOption( - LanguageNames.VisualBasic, optionStore, CodeStyleOptions2.ArithmeticBinaryParentheses, + optionStore, CodeStyleOptions2.ArithmeticBinaryParentheses, BasicVSResources.In_arithmetic_binary_operators, {s_arithmeticBinaryAlwaysForClarity, s_arithmeticBinaryNeverIfUnnecessary}, defaultAddForClarity:=True) AddParenthesesOption( - LanguageNames.VisualBasic, optionStore, CodeStyleOptions2.OtherBinaryParentheses, + optionStore, CodeStyleOptions2.OtherBinaryParentheses, BasicVSResources.In_other_binary_operators, {s_otherBinaryAlwaysForClarity, s_otherBinaryNeverIfUnnecessary}, defaultAddForClarity:=True) AddParenthesesOption( - LanguageNames.VisualBasic, optionStore, CodeStyleOptions2.RelationalBinaryParentheses, + optionStore, CodeStyleOptions2.RelationalBinaryParentheses, BasicVSResources.In_relational_binary_operators, {s_relationalBinaryAlwaysForClarity, s_relationalBinaryNeverIfUnnecessary}, defaultAddForClarity:=True) AddParenthesesOption( - LanguageNames.VisualBasic, optionStore, CodeStyleOptions2.OtherParentheses, + optionStore, CodeStyleOptions2.OtherParentheses, ServicesVSResources.In_other_operators, {s_otherParenthesesAlwaysForClarity, s_otherParenthesesNeverIfUnnecessary}, defaultAddForClarity:=False) @@ -929,7 +929,7 @@ End Class s_avoidUnusedParametersAllMethods } - AddUnusedParameterOption(LanguageNames.VisualBasic, optionStore, parameterPreferencesGroupTitle, examples) + AddUnusedParameterOption(optionStore, parameterPreferencesGroupTitle, examples) End Sub End Class End Namespace diff --git a/src/VisualStudio/VisualBasic/Impl/ProjectSystemShim/VisualBasicCodeModelInstanceFactory.vb b/src/VisualStudio/VisualBasic/Impl/ProjectSystemShim/VisualBasicCodeModelInstanceFactory.vb index 02531ca5caeb1..f39475138216e 100644 --- a/src/VisualStudio/VisualBasic/Impl/ProjectSystemShim/VisualBasicCodeModelInstanceFactory.vb +++ b/src/VisualStudio/VisualBasic/Impl/ProjectSystemShim/VisualBasicCodeModelInstanceFactory.vb @@ -31,7 +31,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ProjectSystemShim ' with the correct "parent" object. ' ' Because the VB project system lacks these hooks, we simulate the same operations that those hooks perform. - Dim document = _project.Workspace.CurrentSolution.GetDocumentIdsWithFilePath(filePath).FirstOrDefault(Function(d) d.ProjectId Is _project.VisualStudioProject.Id) + Dim document = _project.Workspace.CurrentSolution.GetDocumentIdsWithFilePath(filePath).FirstOrDefault(Function(d) d.ProjectId Is _project.ProjectSystemProject.Id) If document Is Nothing Then Throw New ArgumentException(NameOf(filePath)) diff --git a/src/VisualStudio/VisualBasic/Impl/ProjectSystemShim/VisualBasicProject.OptionsProcessor.vb b/src/VisualStudio/VisualBasic/Impl/ProjectSystemShim/VisualBasicProject.OptionsProcessor.vb index 78f53dad6af12..7af845638846a 100644 --- a/src/VisualStudio/VisualBasic/Impl/ProjectSystemShim/VisualBasicProject.OptionsProcessor.vb +++ b/src/VisualStudio/VisualBasic/Impl/ProjectSystemShim/VisualBasicProject.OptionsProcessor.vb @@ -9,6 +9,7 @@ Imports System.Runtime.InteropServices Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.Host Imports Microsoft.CodeAnalysis.VisualBasic +Imports Microsoft.CodeAnalysis.Workspaces.ProjectSystem Imports Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem Imports Microsoft.VisualStudio.LanguageServices.VisualBasic.ProjectSystemShim.Interop @@ -40,7 +41,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ProjectSystemShim ''' Private Shared ReadOnly s_importsCache As Dictionary(Of String, GlobalImport) = New Dictionary(Of String, GlobalImport) - Public Sub New(project As VisualStudioProject, workspaceServices As SolutionServices) + Public Sub New(project As ProjectSystemProject, workspaceServices As SolutionServices) MyBase.New(project, workspaceServices) End Sub diff --git a/src/VisualStudio/VisualBasic/Impl/ProjectSystemShim/VisualBasicProject.vb b/src/VisualStudio/VisualBasic/Impl/ProjectSystemShim/VisualBasicProject.vb index 4ab6f39c5bd0e..6ad885a7cdec2 100644 --- a/src/VisualStudio/VisualBasic/Impl/ProjectSystemShim/VisualBasicProject.vb +++ b/src/VisualStudio/VisualBasic/Impl/ProjectSystemShim/VisualBasicProject.vb @@ -48,8 +48,8 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ProjectSystemShim Dim componentModel = DirectCast(serviceProvider.GetService(GetType(SComponentModel)), IComponentModel) - ProjectCodeModel = componentModel.GetService(Of IProjectCodeModelFactory).CreateProjectCodeModel(VisualStudioProject.Id, New VisualBasicCodeModelInstanceFactory(Me)) - VisualStudioProjectOptionsProcessor = New OptionsProcessor(VisualStudioProject, Workspace.Services.SolutionServices) + ProjectCodeModel = componentModel.GetService(Of IProjectCodeModelFactory).CreateProjectCodeModel(ProjectSystemProject.Id, New VisualBasicCodeModelInstanceFactory(Me)) + VisualStudioProjectOptionsProcessor = New OptionsProcessor(ProjectSystemProject, Workspace.Services.SolutionServices) End Sub Private Shadows Property VisualStudioProjectOptionsProcessor As OptionsProcessor @@ -70,7 +70,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ProjectSystemShim End Sub Public Function AddEmbeddedMetaDataReference(wszFileName As String) As Integer Implements IVbCompilerProject.AddEmbeddedMetaDataReference - VisualStudioProject.AddMetadataReference(wszFileName, New MetadataReferenceProperties(embedInteropTypes:=True)) + ProjectSystemProject.AddMetadataReference(wszFileName, New MetadataReferenceProperties(embedInteropTypes:=True)) Return VSConstants.S_OK End Function @@ -80,7 +80,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ProjectSystemShim _explicitlyAddedRuntimeLibraries.Add(wszFileName) Return VSConstants.S_OK Else - VisualStudioProject.AddMetadataReference(wszFileName, MetadataReferenceProperties.Assembly) + ProjectSystemProject.AddMetadataReference(wszFileName, MetadataReferenceProperties.Assembly) Return VSConstants.S_OK End If End Function @@ -94,7 +94,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ProjectSystemShim Throw New ArgumentException("Unknown type of IVbCompilerProject.", NameOf(pReferencedCompilerProject)) End If - VisualStudioProject.AddProjectReference(New ProjectReference(referencedProject.VisualStudioProject.Id, embedInteropTypes:=True)) + ProjectSystemProject.AddProjectReference(New ProjectReference(referencedProject.ProjectSystemProject.Id, embedInteropTypes:=True)) End Sub Public Shadows Sub AddFile(wszFileName As String, itemid As UInteger, fAddDuringOpen As Boolean) Implements IVbCompilerProject.AddFile @@ -114,7 +114,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ProjectSystemShim Throw New ArgumentException("Unknown type of IVbCompilerProject.", NameOf(pReferencedCompilerProject)) End If - VisualStudioProject.AddProjectReference(New ProjectReference(referencedProject.VisualStudioProject.Id)) + ProjectSystemProject.AddProjectReference(New ProjectReference(referencedProject.ProjectSystemProject.Id)) End Sub Public Sub AddResourceReference(wszFileName As String, wszName As String, fPublic As Boolean, fEmbed As Boolean) Implements IVbCompilerProject.AddResourceReference @@ -198,7 +198,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ProjectSystemShim End Function Public Sub GetEntryPointsList(cItems As Integer, strList() As String, ByVal pcActualItems As IntPtr) Implements IVbCompilerProject.GetEntryPointsList - Dim project = Workspace.CurrentSolution.GetProject(VisualStudioProject.Id) + Dim project = Workspace.CurrentSolution.GetProject(ProjectSystemProject.Id) Dim compilation = project.GetCompilationAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None) GetEntryPointsWorker(compilation, cItems, strList, pcActualItems, findFormsOnly:=False) @@ -270,7 +270,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ProjectSystemShim Return End If - VisualStudioProject.RemoveMetadataReference(wszFileName, VisualStudioProject.GetPropertiesForMetadataReference(wszFileName).Single()) + ProjectSystemProject.RemoveMetadataReference(wszFileName, ProjectSystemProject.GetPropertiesForMetadataReference(wszFileName).Single()) End Sub Public Shadows Sub RemoveProjectReference(pReferencedCompilerProject As IVbCompilerProject) Implements IVbCompilerProject.RemoveProjectReference @@ -282,8 +282,8 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ProjectSystemShim Throw New ArgumentException("Unknown type of IVbCompilerProject.", NameOf(pReferencedCompilerProject)) End If - Dim projectReference = VisualStudioProject.GetProjectReferences().Single(Function(p) p.ProjectId = referencedProject.VisualStudioProject.Id) - VisualStudioProject.RemoveProjectReference(projectReference) + Dim projectReference = ProjectSystemProject.GetProjectReferences().Single(Function(p) p.ProjectId = referencedProject.ProjectSystemProject.Id) + ProjectSystemProject.RemoveProjectReference(projectReference) End Sub Public Sub RenameDefaultNamespace(bstrDefaultNamespace As String) Implements IVbCompilerProject.RenameDefaultNamespace @@ -315,16 +315,16 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ProjectSystemShim VisualStudioProjectOptionsProcessor.SetNewRawOptions(pCompilerOptions) If Not String.IsNullOrEmpty(pCompilerOptions.wszExeName) Then - VisualStudioProject.AssemblyName = Path.GetFileNameWithoutExtension(pCompilerOptions.wszExeName) + ProjectSystemProject.AssemblyName = Path.GetFileNameWithoutExtension(pCompilerOptions.wszExeName) ' Some legacy projects (e.g. Venus IntelliSense project) set '\' as the wszOutputPath. ' /src/venus/project/vb/vbprj/vbintelliproj.cpp ' Ignore paths that are not absolute. If Not String.IsNullOrEmpty(pCompilerOptions.wszOutputPath) Then If PathUtilities.IsAbsolute(pCompilerOptions.wszOutputPath) Then - VisualStudioProject.CompilationOutputAssemblyFilePath = Path.Combine(pCompilerOptions.wszOutputPath, pCompilerOptions.wszExeName) + ProjectSystemProject.CompilationOutputAssemblyFilePath = Path.Combine(pCompilerOptions.wszOutputPath, pCompilerOptions.wszExeName) Else - VisualStudioProject.CompilationOutputAssemblyFilePath = Nothing + ProjectSystemProject.CompilationOutputAssemblyFilePath = Nothing End If End If End If @@ -334,14 +334,14 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ProjectSystemShim _runtimeLibraries = VisualStudioProjectOptionsProcessor.GetRuntimeLibraries(_compilerHost) If Not _runtimeLibraries.SequenceEqual(oldRuntimeLibraries, StringComparer.Ordinal) Then - Using batchScope = VisualStudioProject.CreateBatchScope() + Using batchScope = ProjectSystemProject.CreateBatchScope() ' To keep things simple, we'll just remove everything and add everything back in For Each oldRuntimeLibrary In oldRuntimeLibraries ' If this one was added explicitly in addition to our computation, we don't have to remove it If _explicitlyAddedRuntimeLibraries.Contains(oldRuntimeLibrary) Then _explicitlyAddedRuntimeLibraries.Remove(oldRuntimeLibrary) Else - VisualStudioProject.RemoveMetadataReference(oldRuntimeLibrary, MetadataReferenceProperties.Assembly) + ProjectSystemProject.RemoveMetadataReference(oldRuntimeLibrary, MetadataReferenceProperties.Assembly) End If Next @@ -349,10 +349,10 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ProjectSystemShim newRuntimeLibrary = FileUtilities.NormalizeAbsolutePath(newRuntimeLibrary) ' If we already reference this, just skip it - If VisualStudioProject.ContainsMetadataReference(newRuntimeLibrary, MetadataReferenceProperties.Assembly) Then + If ProjectSystemProject.ContainsMetadataReference(newRuntimeLibrary, MetadataReferenceProperties.Assembly) Then _explicitlyAddedRuntimeLibraries.Add(newRuntimeLibrary) Else - VisualStudioProject.AddMetadataReference(newRuntimeLibrary, MetadataReferenceProperties.Assembly) + ProjectSystemProject.AddMetadataReference(newRuntimeLibrary, MetadataReferenceProperties.Assembly) End If Next End Using diff --git a/src/VisualStudio/VisualBasic/Impl/Venus/VisualBasicContainedLanguage.vb b/src/VisualStudio/VisualBasic/Impl/Venus/VisualBasicContainedLanguage.vb index e8657fae010a0..bff16aebe7dc0 100644 --- a/src/VisualStudio/VisualBasic/Impl/Venus/VisualBasicContainedLanguage.vb +++ b/src/VisualStudio/VisualBasic/Impl/Venus/VisualBasicContainedLanguage.vb @@ -10,6 +10,7 @@ Imports Microsoft.CodeAnalysis.Editor.VisualBasic.Utilities Imports Microsoft.CodeAnalysis.Formatting.Rules Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Syntax +Imports Microsoft.CodeAnalysis.Workspaces.ProjectSystem Imports Microsoft.VisualStudio.ComponentModelHost Imports Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem Imports Microsoft.VisualStudio.LanguageServices.Implementation.Venus @@ -26,7 +27,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Venus Public Sub New(bufferCoordinator As IVsTextBufferCoordinator, componentModel As IComponentModel, - project As VisualStudioProject, + project As ProjectSystemProject, hierarchy As IVsHierarchy, itemid As UInteger, languageServiceGuid As Guid) @@ -40,7 +41,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Venus Public Sub New(bufferCoordinator As IVsTextBufferCoordinator, componentModel As IComponentModel, - project As VisualStudioProject, + project As ProjectSystemProject, languageServiceGuid As Guid) MyBase.New( diff --git a/src/VisualStudio/VisualStudioDiagnosticsToolWindow/OptionPages/ForceLowMemoryMode.cs b/src/VisualStudio/VisualStudioDiagnosticsToolWindow/OptionPages/ForceLowMemoryMode.cs index ec0b8b1dd46b6..f132925996f66 100644 --- a/src/VisualStudio/VisualStudioDiagnosticsToolWindow/OptionPages/ForceLowMemoryMode.cs +++ b/src/VisualStudio/VisualStudioDiagnosticsToolWindow/OptionPages/ForceLowMemoryMode.cs @@ -12,13 +12,8 @@ namespace Roslyn.VisualStudio.DiagnosticsWindow.OptionsPages { internal sealed class ForceLowMemoryMode { - private const string FeatureName = "ForceLowMemoryMode"; - - public static readonly Option2 Enabled = new(FeatureName, "Enabled", defaultValue: false, - storageLocation: new LocalUserProfileStorageLocation(@"Roslyn\ForceLowMemoryMode\Enabled")); - - public static readonly Option2 SizeInMegabytes = new(FeatureName, "SizeInMegabytes", defaultValue: 500, - storageLocation: new LocalUserProfileStorageLocation(@"Roslyn\ForceLowMemoryMode\SizeInMegabytes")); + public static readonly Option2 Enabled = new("ForceLowMemoryMode_Enabled", defaultValue: false); + public static readonly Option2 SizeInMegabytes = new("ForceLowMemoryMode_Enabled", defaultValue: 500); private readonly IGlobalOptionService _globalOptions; private MemoryHogger? _hogger; @@ -34,7 +29,7 @@ public ForceLowMemoryMode(IGlobalOptionService globalOptions) private void Options_OptionChanged(object sender, OptionChangedEventArgs e) { - if (e.Option.Feature == FeatureName) + if (e.Option == Enabled || e.Option == SizeInMegabytes) { RefreshFromSettings(); } diff --git a/src/VisualStudio/VisualStudioDiagnosticsToolWindow/OptionPages/ForceLowMemoryModePage.cs b/src/VisualStudio/VisualStudioDiagnosticsToolWindow/OptionPages/ForceLowMemoryModePage.cs index ca94828e18dd7..9d7a4c26437c3 100644 --- a/src/VisualStudio/VisualStudioDiagnosticsToolWindow/OptionPages/ForceLowMemoryModePage.cs +++ b/src/VisualStudio/VisualStudioDiagnosticsToolWindow/OptionPages/ForceLowMemoryModePage.cs @@ -27,7 +27,7 @@ protected override AbstractOptionPageControl CreateOptionPage(IServiceProvider s internal sealed class Control : InternalOptionsControl { public Control(OptionStore optionStore) - : base(Array.Empty(), optionStore) + : base(Array.Empty(), optionStore) { } diff --git a/src/VisualStudio/VisualStudioDiagnosticsToolWindow/OptionPages/InternalOptionsControl.cs b/src/VisualStudio/VisualStudioDiagnosticsToolWindow/OptionPages/InternalOptionsControl.cs index 275fa3b754acf..9aaad6a769eb4 100644 --- a/src/VisualStudio/VisualStudioDiagnosticsToolWindow/OptionPages/InternalOptionsControl.cs +++ b/src/VisualStudio/VisualStudioDiagnosticsToolWindow/OptionPages/InternalOptionsControl.cs @@ -17,9 +17,9 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options { internal partial class InternalOptionsControl : AbstractOptionPageControl { - private readonly IEnumerable _options; + private readonly IEnumerable _options; - public InternalOptionsControl(IEnumerable options, OptionStore optionStore) + public InternalOptionsControl(IEnumerable options, OptionStore optionStore) : base(optionStore) { _options = options; @@ -123,7 +123,7 @@ protected virtual void AddOptions(Panel panel) } } - protected void AddOption(Panel panel, IOption option, string additional = null) + protected void AddOption(Panel panel, IOption2 option, string additional = null) { var uiElement = CreateControl(option, additional: additional); if (uiElement != null) @@ -132,7 +132,7 @@ protected void AddOption(Panel panel, IOption option, string additional = null) } } - protected void AddPerLanguageOption(Panel panel, IOption option, string languageName, string additional = null) + protected void AddPerLanguageOption(Panel panel, IOption2 option, string languageName, string additional = null) { var uiElement = CreateControl(option, languageName, additional); if (uiElement != null) @@ -141,11 +141,11 @@ protected void AddPerLanguageOption(Panel panel, IOption option, string language } } - private UIElement CreateControl(IOption option, string languageName = null, string additional = null) + private UIElement CreateControl(IOption2 option, string languageName = null, string additional = null) { // Underscores in WPF mean that the next character is the access key for keyboard navigation // but thats not why our option names have underscores. Also removing them looks nicer. - var optionDisplay = option.Name.Replace('_', ' ') + GetLanguage(languageName) + GetAdditionalText(additional); + var optionDisplay = option.Definition.ConfigName.Replace('_', ' ') + GetLanguage(languageName) + GetAdditionalText(additional); if (option.Type == typeof(bool)) { @@ -192,7 +192,7 @@ private static string GetLanguage(string languageName) return " [" + languageName + "]"; } - private void BindToCheckBox(CheckBox checkBox, IOption option, string languageName = null) + private void BindToCheckBox(CheckBox checkBox, IOption2 option, string languageName = null) { if (languageName == null) { @@ -203,7 +203,7 @@ private void BindToCheckBox(CheckBox checkBox, IOption option, string languageNa BindToOption(checkBox, (PerLanguageOption2)option, languageName); } - private void BindToTextBox(TextBox textBox, IOption option, string languageName = null) + private void BindToTextBox(TextBox textBox, IOption2 option, string languageName = null) { if (languageName == null) { diff --git a/src/VisualStudio/Xaml/Impl/Implementation/XamlProjectService.cs b/src/VisualStudio/Xaml/Impl/Implementation/XamlProjectService.cs index 4e2281b555d67..cb38bacce4f12 100644 --- a/src/VisualStudio/Xaml/Impl/Implementation/XamlProjectService.cs +++ b/src/VisualStudio/Xaml/Impl/Implementation/XamlProjectService.cs @@ -15,6 +15,7 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Workspaces.ProjectSystem; using Microsoft.CodeAnalysis.Xaml.Diagnostics.Analyzers; using Microsoft.VisualStudio.Editor; using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; @@ -33,7 +34,7 @@ internal sealed partial class XamlProjectService private readonly VisualStudioProjectFactory _visualStudioProjectFactory; private readonly IVsEditorAdaptersFactoryService _editorAdaptersFactory; private readonly IThreadingContext _threadingContext; - private readonly Dictionary _xamlProjects = new(); + private readonly Dictionary _xamlProjects = new(); private readonly ConcurrentDictionary _documentIds = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); private RunningDocumentTable? _rdt; diff --git a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpCodeGenerationService.cs b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpCodeGenerationService.cs index 92866b9f883e6..fde42021bd778 100644 --- a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpCodeGenerationService.cs +++ b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpCodeGenerationService.cs @@ -33,7 +33,7 @@ public CSharpCodeGenerationService(HostLanguageServices languageServices) public override CodeGenerationOptions DefaultOptions => CSharpCodeGenerationOptions.Default; - public override CodeGenerationOptions GetCodeGenerationOptions(AnalyzerConfigOptions options, CodeGenerationOptions? fallbackOptions) + public override CodeGenerationOptions GetCodeGenerationOptions(IOptionsReader options, CodeGenerationOptions? fallbackOptions) => options.GetCSharpCodeGenerationOptions((CSharpCodeGenerationOptions?)fallbackOptions); public override CodeGenerationDestination GetDestination(SyntaxNode node) diff --git a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs index 6ea09a0e39c13..227f63fcc70af 100644 --- a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs +++ b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs @@ -14,7 +14,6 @@ using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.FindSymbols.Finders; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -227,6 +226,9 @@ public override SyntaxNode MethodDeclaration( { var hasBody = !modifiers.IsAbstract && (!modifiers.IsPartial || statements != null); + if (!hasBody) + modifiers -= DeclarationModifiers.Async; + return SyntaxFactory.MethodDeclaration( attributeLists: default, modifiers: AsModifierList(accessibility, modifiers, SyntaxKind.MethodDeclaration), @@ -1648,8 +1650,8 @@ private static SyntaxTokenList AsModifierList(Accessibility accessibility, Decla list.Add(SyntaxFactory.Token(SyntaxKind.ProtectedKeyword)); break; case Accessibility.ProtectedOrInternal: - list.Add(SyntaxFactory.Token(SyntaxKind.InternalKeyword)); list.Add(SyntaxFactory.Token(SyntaxKind.ProtectedKeyword)); + list.Add(SyntaxFactory.Token(SyntaxKind.InternalKeyword)); break; case Accessibility.ProtectedAndInternal: list.Add(SyntaxFactory.Token(SyntaxKind.PrivateKeyword)); diff --git a/src/Workspaces/CSharp/Portable/CodeStyle/CSharpCodeStyleOptionsProvider.cs b/src/Workspaces/CSharp/Portable/CodeStyle/CSharpCodeStyleOptionsProvider.cs deleted file mode 100644 index 522e0462fcedf..0000000000000 --- a/src/Workspaces/CSharp/Portable/CodeStyle/CSharpCodeStyleOptionsProvider.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections.Immutable; -using System.Composition; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Options.Providers; - -namespace Microsoft.CodeAnalysis.CSharp.CodeStyle -{ - [ExportSolutionOptionProvider(LanguageNames.CSharp), Shared] - internal sealed class CSharpSolutionCodeStyleOptionsProvider : IOptionProvider - { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpSolutionCodeStyleOptionsProvider() - { - } - - public ImmutableArray Options { get; } = CSharpCodeStyleOptions.AllOptions.As(); - } -} diff --git a/src/Workspaces/CSharp/Portable/CodeStyle/CSharpCodeStyleService.cs b/src/Workspaces/CSharp/Portable/CodeStyle/CSharpCodeStyleService.cs index 53e97e51cf884..08418705da35d 100644 --- a/src/Workspaces/CSharp/Portable/CodeStyle/CSharpCodeStyleService.cs +++ b/src/Workspaces/CSharp/Portable/CodeStyle/CSharpCodeStyleService.cs @@ -6,6 +6,7 @@ using System.Composition; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.CSharp.CodeStyle; @@ -20,4 +21,48 @@ public CSharpCodeStyleService() public IdeCodeStyleOptions DefaultOptions => CSharpIdeCodeStyleOptions.Default; + + public IdeCodeStyleOptions GetIdeCodeStyleOptions(IOptionsReader options, IdeCodeStyleOptions? fallbackOptions) + => options.GetCSharpCodeStyleOptions((CSharpIdeCodeStyleOptions?)fallbackOptions); +} + +internal static class CSharpIdeCodeStyleOptionsProviders +{ + public static CSharpIdeCodeStyleOptions GetCSharpCodeStyleOptions(this IOptionsReader options, CSharpIdeCodeStyleOptions? fallbackOptions) + { + fallbackOptions ??= CSharpIdeCodeStyleOptions.Default; + + return new() + { + Common = options.GetCommonCodeStyleOptions(LanguageNames.CSharp, fallbackOptions.Common), + ImplicitObjectCreationWhenTypeIsApparent = options.GetOption(CSharpCodeStyleOptions.ImplicitObjectCreationWhenTypeIsApparent, fallbackOptions.ImplicitObjectCreationWhenTypeIsApparent), + PreferNullCheckOverTypeCheck = options.GetOption(CSharpCodeStyleOptions.PreferNullCheckOverTypeCheck, fallbackOptions.PreferNullCheckOverTypeCheck), + AllowBlankLinesBetweenConsecutiveBraces = options.GetOption(CSharpCodeStyleOptions.AllowBlankLinesBetweenConsecutiveBraces, fallbackOptions.AllowBlankLinesBetweenConsecutiveBraces), + AllowBlankLineAfterColonInConstructorInitializer = options.GetOption(CSharpCodeStyleOptions.AllowBlankLineAfterColonInConstructorInitializer, fallbackOptions.AllowBlankLineAfterColonInConstructorInitializer), + AllowBlankLineAfterTokenInConditionalExpression = options.GetOption(CSharpCodeStyleOptions.AllowBlankLineAfterTokenInConditionalExpression, fallbackOptions.AllowBlankLineAfterTokenInConditionalExpression), + AllowBlankLineAfterTokenInArrowExpressionClause = options.GetOption(CSharpCodeStyleOptions.AllowBlankLineAfterTokenInArrowExpressionClause, fallbackOptions.AllowBlankLineAfterTokenInArrowExpressionClause), + PreferConditionalDelegateCall = options.GetOption(CSharpCodeStyleOptions.PreferConditionalDelegateCall, fallbackOptions.PreferConditionalDelegateCall), + PreferSwitchExpression = options.GetOption(CSharpCodeStyleOptions.PreferSwitchExpression, fallbackOptions.PreferSwitchExpression), + PreferPatternMatching = options.GetOption(CSharpCodeStyleOptions.PreferPatternMatching, fallbackOptions.PreferPatternMatching), + PreferPatternMatchingOverAsWithNullCheck = options.GetOption(CSharpCodeStyleOptions.PreferPatternMatchingOverAsWithNullCheck, fallbackOptions.PreferPatternMatchingOverAsWithNullCheck), + PreferPatternMatchingOverIsWithCastCheck = options.GetOption(CSharpCodeStyleOptions.PreferPatternMatchingOverIsWithCastCheck, fallbackOptions.PreferPatternMatchingOverIsWithCastCheck), + PreferNotPattern = options.GetOption(CSharpCodeStyleOptions.PreferNotPattern, fallbackOptions.PreferNotPattern), + PreferExtendedPropertyPattern = options.GetOption(CSharpCodeStyleOptions.PreferExtendedPropertyPattern, fallbackOptions.PreferExtendedPropertyPattern), + PreferInlinedVariableDeclaration = options.GetOption(CSharpCodeStyleOptions.PreferInlinedVariableDeclaration, fallbackOptions.PreferInlinedVariableDeclaration), + PreferDeconstructedVariableDeclaration = options.GetOption(CSharpCodeStyleOptions.PreferDeconstructedVariableDeclaration, fallbackOptions.PreferDeconstructedVariableDeclaration), + PreferIndexOperator = options.GetOption(CSharpCodeStyleOptions.PreferIndexOperator, fallbackOptions.PreferIndexOperator), + PreferRangeOperator = options.GetOption(CSharpCodeStyleOptions.PreferRangeOperator, fallbackOptions.PreferRangeOperator), + PreferUtf8StringLiterals = options.GetOption(CSharpCodeStyleOptions.PreferUtf8StringLiterals, fallbackOptions.PreferUtf8StringLiterals), + PreferredModifierOrder = options.GetOption(CSharpCodeStyleOptions.PreferredModifierOrder, fallbackOptions.PreferredModifierOrder), + PreferSimpleUsingStatement = options.GetOption(CSharpCodeStyleOptions.PreferSimpleUsingStatement, fallbackOptions.PreferSimpleUsingStatement), + PreferLocalOverAnonymousFunction = options.GetOption(CSharpCodeStyleOptions.PreferLocalOverAnonymousFunction, fallbackOptions.PreferLocalOverAnonymousFunction), + PreferTupleSwap = options.GetOption(CSharpCodeStyleOptions.PreferTupleSwap, fallbackOptions.PreferTupleSwap), + UnusedValueExpressionStatement = options.GetOption(CSharpCodeStyleOptions.UnusedValueExpressionStatement, fallbackOptions.UnusedValueExpressionStatement), + UnusedValueAssignment = options.GetOption(CSharpCodeStyleOptions.UnusedValueAssignment, fallbackOptions.UnusedValueAssignment), + PreferMethodGroupConversion = options.GetOption(CSharpCodeStyleOptions.PreferMethodGroupConversion, fallbackOptions.PreferMethodGroupConversion), + PreferExpressionBodiedLambdas = options.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedLambdas, fallbackOptions.PreferExpressionBodiedLambdas), + PreferReadOnlyStruct = options.GetOption(CSharpCodeStyleOptions.PreferReadOnlyStruct, fallbackOptions.PreferReadOnlyStruct), + PreferStaticLocalFunction = options.GetOption(CSharpCodeStyleOptions.PreferStaticLocalFunction, fallbackOptions.PreferStaticLocalFunction) + }; + } } diff --git a/src/Workspaces/CSharp/Portable/Formatting/CSharpFormattingOptions.cs b/src/Workspaces/CSharp/Portable/Formatting/CSharpFormattingOptions.cs index fe845eccf420c..7e7c2151b117f 100644 --- a/src/Workspaces/CSharp/Portable/Formatting/CSharpFormattingOptions.cs +++ b/src/Workspaces/CSharp/Portable/Formatting/CSharpFormattingOptions.cs @@ -2,6 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#pragma warning disable RS0030 // Do not used banned APIs + +using System.Collections.Immutable; using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.CSharp.Formatting @@ -9,145 +12,179 @@ namespace Microsoft.CodeAnalysis.CSharp.Formatting /// public static class CSharpFormattingOptions { + private const string PublicFeatureName = "CSharpFormattingOptions"; + + private static Option CreateNewLineForBracesOption(string publicName, NewLineBeforeOpenBracePlacement flag) + => new( + feature: PublicFeatureName, + name: publicName, + group: CSharpFormattingOptionGroups.NewLine, + defaultValue: CSharpFormattingOptions2.NewLineBeforeOpenBrace.DefaultValue.HasFlag(flag), + storageLocations: ImmutableArray.Empty, + storageMapping: new NewLineForBracesInternalStorageMapping(CSharpFormattingOptions2.NewLineBeforeOpenBrace, flag), + isEditorConfigOption: true); + + private static Option CreateSpaceWithinOption(string publicName, SpacePlacementWithinParentheses flag) + => new( + feature: PublicFeatureName, + name: publicName, + group: CSharpFormattingOptionGroups.Spacing, + defaultValue: CSharpFormattingOptions2.SpaceBetweenParentheses.DefaultValue.HasFlag(flag), + storageLocations: ImmutableArray.Empty, + storageMapping: new SpacePlacementInternalStorageMapping(CSharpFormattingOptions2.SpaceBetweenParentheses, flag), + isEditorConfigOption: true); + + private sealed class NewLineForBracesInternalStorageMapping : OptionStorageMapping + { + private readonly NewLineBeforeOpenBracePlacement _flag; + + public NewLineForBracesInternalStorageMapping(IOption2 internalOption, NewLineBeforeOpenBracePlacement flag) + : base(internalOption) + { + _flag = flag; + } + + public override object? ToPublicOptionValue(object? internalValue) + => ((NewLineBeforeOpenBracePlacement)internalValue!).HasFlag(_flag); + + public override object? UpdateInternalOptionValue(object? currentInternalValue, object? newPublicValue) + => ((NewLineBeforeOpenBracePlacement)currentInternalValue!).WithFlagValue(_flag, (bool)newPublicValue!); + } + + private sealed class SpacePlacementInternalStorageMapping : OptionStorageMapping + { + private readonly SpacePlacementWithinParentheses _flag; + + public SpacePlacementInternalStorageMapping(IOption2 internalOption, SpacePlacementWithinParentheses flag) + : base(internalOption) + { + _flag = flag; + } + + public override object? ToPublicOptionValue(object? internalValue) + => ((SpacePlacementWithinParentheses)internalValue!).HasFlag(_flag); + + public override object? UpdateInternalOptionValue(object? currentInternalValue, object? newPublicValue) + => ((SpacePlacementWithinParentheses)currentInternalValue!).WithFlagValue(_flag, (bool)newPublicValue!); + } + /// - public static Option SpacingAfterMethodDeclarationName { get; } = (Option)CSharpFormattingOptions2.SpacingAfterMethodDeclarationName!; + public static Option SpacingAfterMethodDeclarationName { get; } = CSharpFormattingOptions2.SpacingAfterMethodDeclarationName.ToPublicOption(); /// - public static Option SpaceWithinMethodDeclarationParenthesis { get; } = (Option)CSharpFormattingOptions2.SpaceWithinMethodDeclarationParenthesis!; + public static Option SpaceWithinMethodDeclarationParenthesis { get; } = CSharpFormattingOptions2.SpaceWithinMethodDeclarationParenthesis.ToPublicOption(); /// - public static Option SpaceBetweenEmptyMethodDeclarationParentheses { get; } = (Option)CSharpFormattingOptions2.SpaceBetweenEmptyMethodDeclarationParentheses!; + public static Option SpaceBetweenEmptyMethodDeclarationParentheses { get; } = CSharpFormattingOptions2.SpaceBetweenEmptyMethodDeclarationParentheses.ToPublicOption(); /// - public static Option SpaceAfterMethodCallName { get; } = (Option)CSharpFormattingOptions2.SpaceAfterMethodCallName!; + public static Option SpaceAfterMethodCallName { get; } = CSharpFormattingOptions2.SpaceAfterMethodCallName.ToPublicOption(); /// - public static Option SpaceWithinMethodCallParentheses { get; } = (Option)CSharpFormattingOptions2.SpaceWithinMethodCallParentheses!; + public static Option SpaceWithinMethodCallParentheses { get; } = CSharpFormattingOptions2.SpaceWithinMethodCallParentheses.ToPublicOption(); /// - public static Option SpaceBetweenEmptyMethodCallParentheses { get; } = (Option)CSharpFormattingOptions2.SpaceBetweenEmptyMethodCallParentheses!; + public static Option SpaceBetweenEmptyMethodCallParentheses { get; } = CSharpFormattingOptions2.SpaceBetweenEmptyMethodCallParentheses.ToPublicOption(); /// - public static Option SpaceAfterControlFlowStatementKeyword { get; } = (Option)CSharpFormattingOptions2.SpaceAfterControlFlowStatementKeyword!; - - /// - public static Option SpaceWithinExpressionParentheses { get; } = (Option)CSharpFormattingOptions2.SpaceWithinExpressionParentheses!; - - /// - public static Option SpaceWithinCastParentheses { get; } = (Option)CSharpFormattingOptions2.SpaceWithinCastParentheses!; + public static Option SpaceAfterControlFlowStatementKeyword { get; } = CSharpFormattingOptions2.SpaceAfterControlFlowStatementKeyword.ToPublicOption(); - /// - public static Option SpaceWithinOtherParentheses { get; } = (Option)CSharpFormattingOptions2.SpaceWithinOtherParentheses!; + public static Option SpaceWithinExpressionParentheses { get; } = CreateSpaceWithinOption("SpaceWithinExpressionParentheses", SpacePlacementWithinParentheses.Expressions); + public static Option SpaceWithinCastParentheses { get; } = CreateSpaceWithinOption("SpaceWithinCastParentheses", SpacePlacementWithinParentheses.TypeCasts); + public static Option SpaceWithinOtherParentheses { get; } = CreateSpaceWithinOption("SpaceWithinOtherParentheses", SpacePlacementWithinParentheses.ControlFlowStatements); /// - public static Option SpaceAfterCast { get; } = (Option)CSharpFormattingOptions2.SpaceAfterCast!; + public static Option SpaceAfterCast { get; } = CSharpFormattingOptions2.SpaceAfterCast.ToPublicOption(); /// - public static Option SpacesIgnoreAroundVariableDeclaration { get; } = (Option)CSharpFormattingOptions2.SpacesIgnoreAroundVariableDeclaration!; + public static Option SpacesIgnoreAroundVariableDeclaration { get; } = CSharpFormattingOptions2.SpacesIgnoreAroundVariableDeclaration.ToPublicOption(); /// - public static Option SpaceBeforeOpenSquareBracket { get; } = (Option)CSharpFormattingOptions2.SpaceBeforeOpenSquareBracket!; + public static Option SpaceBeforeOpenSquareBracket { get; } = CSharpFormattingOptions2.SpaceBeforeOpenSquareBracket.ToPublicOption(); /// - public static Option SpaceBetweenEmptySquareBrackets { get; } = (Option)CSharpFormattingOptions2.SpaceBetweenEmptySquareBrackets!; + public static Option SpaceBetweenEmptySquareBrackets { get; } = CSharpFormattingOptions2.SpaceBetweenEmptySquareBrackets.ToPublicOption(); /// - public static Option SpaceWithinSquareBrackets { get; } = (Option)CSharpFormattingOptions2.SpaceWithinSquareBrackets!; + public static Option SpaceWithinSquareBrackets { get; } = CSharpFormattingOptions2.SpaceWithinSquareBrackets.ToPublicOption(); /// - public static Option SpaceAfterColonInBaseTypeDeclaration { get; } = (Option)CSharpFormattingOptions2.SpaceAfterColonInBaseTypeDeclaration!; + public static Option SpaceAfterColonInBaseTypeDeclaration { get; } = CSharpFormattingOptions2.SpaceAfterColonInBaseTypeDeclaration.ToPublicOption(); /// - public static Option SpaceAfterComma { get; } = (Option)CSharpFormattingOptions2.SpaceAfterComma!; + public static Option SpaceAfterComma { get; } = CSharpFormattingOptions2.SpaceAfterComma.ToPublicOption(); /// - public static Option SpaceAfterDot { get; } = (Option)CSharpFormattingOptions2.SpaceAfterDot!; + public static Option SpaceAfterDot { get; } = CSharpFormattingOptions2.SpaceAfterDot.ToPublicOption(); /// - public static Option SpaceAfterSemicolonsInForStatement { get; } = (Option)CSharpFormattingOptions2.SpaceAfterSemicolonsInForStatement!; + public static Option SpaceAfterSemicolonsInForStatement { get; } = CSharpFormattingOptions2.SpaceAfterSemicolonsInForStatement.ToPublicOption(); /// - public static Option SpaceBeforeColonInBaseTypeDeclaration { get; } = (Option)CSharpFormattingOptions2.SpaceBeforeColonInBaseTypeDeclaration!; + public static Option SpaceBeforeColonInBaseTypeDeclaration { get; } = CSharpFormattingOptions2.SpaceBeforeColonInBaseTypeDeclaration.ToPublicOption(); /// - public static Option SpaceBeforeComma { get; } = (Option)CSharpFormattingOptions2.SpaceBeforeComma!; + public static Option SpaceBeforeComma { get; } = CSharpFormattingOptions2.SpaceBeforeComma.ToPublicOption(); /// - public static Option SpaceBeforeDot { get; } = (Option)CSharpFormattingOptions2.SpaceBeforeDot!; + public static Option SpaceBeforeDot { get; } = CSharpFormattingOptions2.SpaceBeforeDot.ToPublicOption(); /// - public static Option SpaceBeforeSemicolonsInForStatement { get; } = (Option)CSharpFormattingOptions2.SpaceBeforeSemicolonsInForStatement!; + public static Option SpaceBeforeSemicolonsInForStatement { get; } = CSharpFormattingOptions2.SpaceBeforeSemicolonsInForStatement.ToPublicOption(); /// - public static Option SpacingAroundBinaryOperator { get; } = (Option)CSharpFormattingOptions2.SpacingAroundBinaryOperator!; + public static Option SpacingAroundBinaryOperator { get; } = CSharpFormattingOptions2.SpacingAroundBinaryOperator.ToPublicOption(); /// - public static Option IndentBraces { get; } = (Option)CSharpFormattingOptions2.IndentBraces!; + public static Option IndentBraces { get; } = CSharpFormattingOptions2.IndentBraces.ToPublicOption(); /// - public static Option IndentBlock { get; } = (Option)CSharpFormattingOptions2.IndentBlock!; + public static Option IndentBlock { get; } = CSharpFormattingOptions2.IndentBlock.ToPublicOption(); /// - public static Option IndentSwitchSection { get; } = (Option)CSharpFormattingOptions2.IndentSwitchSection!; + public static Option IndentSwitchSection { get; } = CSharpFormattingOptions2.IndentSwitchSection.ToPublicOption(); /// - public static Option IndentSwitchCaseSection { get; } = (Option)CSharpFormattingOptions2.IndentSwitchCaseSection!; + public static Option IndentSwitchCaseSection { get; } = CSharpFormattingOptions2.IndentSwitchCaseSection.ToPublicOption(); /// - public static Option IndentSwitchCaseSectionWhenBlock { get; } = (Option)CSharpFormattingOptions2.IndentSwitchCaseSectionWhenBlock!; + public static Option IndentSwitchCaseSectionWhenBlock { get; } = CSharpFormattingOptions2.IndentSwitchCaseSectionWhenBlock.ToPublicOption(); /// - public static Option LabelPositioning { get; } = (Option)CSharpFormattingOptions2.LabelPositioning!; + public static Option LabelPositioning { get; } = CSharpFormattingOptions2.LabelPositioning.ToPublicOption(); /// - public static Option WrappingPreserveSingleLine { get; } = (Option)CSharpFormattingOptions2.WrappingPreserveSingleLine!; + public static Option WrappingPreserveSingleLine { get; } = CSharpFormattingOptions2.WrappingPreserveSingleLine.ToPublicOption(); /// - public static Option WrappingKeepStatementsOnSingleLine { get; } = (Option)CSharpFormattingOptions2.WrappingKeepStatementsOnSingleLine!; - - /// - public static Option NewLinesForBracesInTypes { get; } = (Option)CSharpFormattingOptions2.NewLinesForBracesInTypes!; - - /// - public static Option NewLinesForBracesInMethods { get; } = (Option)CSharpFormattingOptions2.NewLinesForBracesInMethods!; - - /// - public static Option NewLinesForBracesInProperties { get; } = (Option)CSharpFormattingOptions2.NewLinesForBracesInProperties!; - - /// - public static Option NewLinesForBracesInAccessors { get; } = (Option)CSharpFormattingOptions2.NewLinesForBracesInAccessors!; - - /// - public static Option NewLinesForBracesInAnonymousMethods { get; } = (Option)CSharpFormattingOptions2.NewLinesForBracesInAnonymousMethods!; - - /// - public static Option NewLinesForBracesInControlBlocks { get; } = (Option)CSharpFormattingOptions2.NewLinesForBracesInControlBlocks!; - - /// - public static Option NewLinesForBracesInAnonymousTypes { get; } = (Option)CSharpFormattingOptions2.NewLinesForBracesInAnonymousTypes!; - - /// - public static Option NewLinesForBracesInObjectCollectionArrayInitializers { get; } = (Option)CSharpFormattingOptions2.NewLinesForBracesInObjectCollectionArrayInitializers!; - - /// - public static Option NewLinesForBracesInLambdaExpressionBody { get; } = (Option)CSharpFormattingOptions2.NewLinesForBracesInLambdaExpressionBody!; + public static Option WrappingKeepStatementsOnSingleLine { get; } = CSharpFormattingOptions2.WrappingKeepStatementsOnSingleLine.ToPublicOption(); + + public static Option NewLinesForBracesInTypes { get; } = CreateNewLineForBracesOption("NewLinesForBracesInTypes", NewLineBeforeOpenBracePlacement.Types); + public static Option NewLinesForBracesInMethods { get; } = CreateNewLineForBracesOption("NewLinesForBracesInMethods", NewLineBeforeOpenBracePlacement.Methods); + public static Option NewLinesForBracesInProperties { get; } = CreateNewLineForBracesOption("NewLinesForBracesInProperties", NewLineBeforeOpenBracePlacement.Properties); + public static Option NewLinesForBracesInAccessors { get; } = CreateNewLineForBracesOption("NewLinesForBracesInAccessors", NewLineBeforeOpenBracePlacement.Accessors); + public static Option NewLinesForBracesInAnonymousMethods { get; } = CreateNewLineForBracesOption("NewLinesForBracesInAnonymousMethods", NewLineBeforeOpenBracePlacement.AnonymousMethods); + public static Option NewLinesForBracesInControlBlocks { get; } = CreateNewLineForBracesOption("NewLinesForBracesInControlBlocks", NewLineBeforeOpenBracePlacement.ControlBlocks); + public static Option NewLinesForBracesInAnonymousTypes { get; } = CreateNewLineForBracesOption("NewLinesForBracesInAnonymousTypes", NewLineBeforeOpenBracePlacement.AnonymousTypes); + public static Option NewLinesForBracesInObjectCollectionArrayInitializers { get; } = CreateNewLineForBracesOption("NewLinesForBracesInObjectCollectionArrayInitializers", NewLineBeforeOpenBracePlacement.ObjectCollectionArrayInitializers); + public static Option NewLinesForBracesInLambdaExpressionBody { get; } = CreateNewLineForBracesOption("NewLinesForBracesInLambdaExpressionBody", NewLineBeforeOpenBracePlacement.LambdaExpressionBody); /// - public static Option NewLineForElse { get; } = (Option)CSharpFormattingOptions2.NewLineForElse!; + public static Option NewLineForElse { get; } = CSharpFormattingOptions2.NewLineForElse.ToPublicOption(); /// - public static Option NewLineForCatch { get; } = (Option)CSharpFormattingOptions2.NewLineForCatch!; + public static Option NewLineForCatch { get; } = CSharpFormattingOptions2.NewLineForCatch.ToPublicOption(); /// - public static Option NewLineForFinally { get; } = (Option)CSharpFormattingOptions2.NewLineForFinally!; + public static Option NewLineForFinally { get; } = CSharpFormattingOptions2.NewLineForFinally.ToPublicOption(); /// - public static Option NewLineForMembersInObjectInit { get; } = (Option)CSharpFormattingOptions2.NewLineForMembersInObjectInit!; + public static Option NewLineForMembersInObjectInit { get; } = CSharpFormattingOptions2.NewLineForMembersInObjectInit.ToPublicOption(); /// - public static Option NewLineForMembersInAnonymousTypes { get; } = (Option)CSharpFormattingOptions2.NewLineForMembersInAnonymousTypes!; + public static Option NewLineForMembersInAnonymousTypes { get; } = CSharpFormattingOptions2.NewLineForMembersInAnonymousTypes.ToPublicOption(); /// - public static Option NewLineForClausesInQuery { get; } = (Option)CSharpFormattingOptions2.NewLineForClausesInQuery!; + public static Option NewLineForClausesInQuery { get; } = CSharpFormattingOptions2.NewLineForClausesInQuery.ToPublicOption(); } } diff --git a/src/Workspaces/CSharp/Portable/Formatting/CSharpFormattingOptionsProvider.cs b/src/Workspaces/CSharp/Portable/Formatting/CSharpFormattingOptionsProvider.cs deleted file mode 100644 index 132e6f6ce31ee..0000000000000 --- a/src/Workspaces/CSharp/Portable/Formatting/CSharpFormattingOptionsProvider.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections.Immutable; -using System.Composition; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Options.Providers; - -namespace Microsoft.CodeAnalysis.CSharp.Formatting -{ - [ExportSolutionOptionProvider(LanguageNames.CSharp), Shared] - internal sealed class CSharpFormattingOptionsProvider : IOptionProvider - { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpFormattingOptionsProvider() - { - } - - public ImmutableArray Options { get; } = CSharpFormattingOptions2.AllOptions.As(); - } -} diff --git a/src/Workspaces/CSharp/Portable/Simplification/CSharpSimplificationService.cs b/src/Workspaces/CSharp/Portable/Simplification/CSharpSimplificationService.cs index 4792d141b4c2f..664afa8315637 100644 --- a/src/Workspaces/CSharp/Portable/Simplification/CSharpSimplificationService.cs +++ b/src/Workspaces/CSharp/Portable/Simplification/CSharpSimplificationService.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Internal.Log; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Simplification; using Roslyn.Utilities; @@ -47,7 +48,7 @@ public CSharpSimplificationService() : base(s_reducers) public override SimplifierOptions DefaultOptions => CSharpSimplifierOptions.Default; - public override SimplifierOptions GetSimplifierOptions(AnalyzerConfigOptions options, SimplifierOptions? fallbackOptions) + public override SimplifierOptions GetSimplifierOptions(IOptionsReader options, SimplifierOptions? fallbackOptions) => options.GetCSharpSimplifierOptions((CSharpSimplifierOptions?)fallbackOptions); public override SyntaxNode Expand(SyntaxNode node, SemanticModel semanticModel, SyntaxAnnotation? annotationForReplacedAliasIdentifier, Func? expandInsideNode, bool expandParameter, CancellationToken cancellationToken) diff --git a/src/Workspaces/CSharpTest/CodeGeneration/SyntaxGeneratorTests.cs b/src/Workspaces/CSharpTest/CodeGeneration/SyntaxGeneratorTests.cs index 44fd0ac0e4115..0d447012022a9 100644 --- a/src/Workspaces/CSharpTest/CodeGeneration/SyntaxGeneratorTests.cs +++ b/src/Workspaces/CSharpTest/CodeGeneration/SyntaxGeneratorTests.cs @@ -840,6 +840,10 @@ public void TestMethodDeclarations() VerifySyntax( Generator.MethodDeclaration("m", modifiers: DeclarationModifiers.Partial, statements: new[] { Generator.IdentifierName("y") }), "partial void m()\r\n{\r\n y;\r\n}"); + + VerifySyntax( + Generator.MethodDeclaration("m", modifiers: DeclarationModifiers.Partial | DeclarationModifiers.Async, statements: null), + "partial void m();"); } [Fact] @@ -2714,6 +2718,16 @@ public void TestAddVirtualModifierToRequiredProperty() VerifySyntax(updatedProperty, "public virtual required int P { get; }"); } + [Theory, WorkItem(66295, "https://github.com/dotnet/roslyn/issues/66295")] + [InlineData("private protected")] + [InlineData("protected internal")] + public void TestCompoundAccessibilityModifierKeywordsOrder(string modifier) + { + var property = (PropertyDeclarationSyntax)SyntaxFactory.ParseMemberDeclaration($$"""{{modifier}} int P { get; }"""); + var updatedProperty = Generator.WithModifiers(property, Generator.GetModifiers(property).WithIsRequired(true)); + VerifySyntax(updatedProperty, $$"""{{modifier}} required int P { get; }"""); + } + [Fact] public void TestGetType() { @@ -4024,7 +4038,7 @@ public void TestClassModifiers1() } [Fact, WorkItem(1084965, " https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1084965")] - public void TestMethodModifiers1() + public void TestMethodModifiers() { TestModifiersAsync(DeclarationModifiers.Sealed | DeclarationModifiers.Override, @" @@ -4034,6 +4048,17 @@ class C }"); } + [Fact, WorkItem(66170, "https://github.com/dotnet/roslyn/issues/66170")] + public void TestMethodModifiers2() + { + TestModifiersAsync(DeclarationModifiers.ReadOnly, + @" +struct S +{ + [|public readonly void M() { }|] +}"); + } + [Fact] public void TestAsyncMethodModifier() { @@ -4102,6 +4127,16 @@ class C }"); } + [Fact, WorkItem(65834, "https://github.com/dotnet/roslyn/issues/65834")] + public void TestStructModifiers1() + { + TestModifiersAsync(DeclarationModifiers.ReadOnly | DeclarationModifiers.Sealed, + @" +public readonly struct [|S|] +{ +}"); + } + private static void TestModifiersAsync(DeclarationModifiers modifiers, string markup) { MarkupTestFile.GetSpan(markup, out var code, out var span); diff --git a/src/Workspaces/CSharpTest/Formatting/FormattingTests.cs b/src/Workspaces/CSharpTest/Formatting/FormattingTests.cs index e87981bbf5f1d..86d350c972f94 100644 --- a/src/Workspaces/CSharpTest/Formatting/FormattingTests.cs +++ b/src/Workspaces/CSharpTest/Formatting/FormattingTests.cs @@ -960,7 +960,7 @@ public async Task RelativeIndentationToFirstTokenInBaseTokenWithObjectInitialize { var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - { CSharpFormattingOptions2.NewLinesForBracesInObjectCollectionArrayInitializers, false } + { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ObjectCollectionArrayInitializers, false) }, }; await AssertFormatAsync(@"class Program { @@ -1035,7 +1035,7 @@ public async Task IndentUserSettingNonDefaultTest_OpenBracesOfLambdaWithNoNewLin { IndentBlock, false }, { IndentSwitchSection, false }, { IndentSwitchCaseSection, false }, - { NewLinesForBracesInLambdaExpressionBody, false }, + { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.LambdaExpressionBody, false) }, { LabelPositioning, LabelPositionOptions.LeftMost } }; @@ -1881,13 +1881,7 @@ public async Task NewLineForOpenBracesNonDefault() { var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - { NewLinesForBracesInTypes, false }, - { NewLinesForBracesInMethods, false }, - { NewLinesForBracesInAnonymousMethods, false }, - { NewLinesForBracesInControlBlocks, false }, - { NewLinesForBracesInAnonymousTypes, false }, - { NewLinesForBracesInObjectCollectionArrayInitializers, false }, - { NewLinesForBracesInLambdaExpressionBody, false } + { NewLineBeforeOpenBrace, NewLineBeforeOpenBracePlacement.None } }; await AssertFormatAsync(@"class f00 { void br() { @@ -2137,7 +2131,7 @@ public async Task NoNewLineForElseChecksBraceOwner() var changingOptions = new OptionsCollection(LanguageNames.CSharp) { { NewLineForElse, false }, - { NewLinesForBracesInControlBlocks, false }, + { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ControlBlocks, false) } }; await AssertFormatAsync(@"class Class @@ -6123,7 +6117,11 @@ public void goo() { } } }"; - var optionSet = new OptionsCollection(LanguageNames.CSharp) { { CSharpFormattingOptions2.SpaceWithinOtherParentheses, true } }; + var optionSet = new OptionsCollection(LanguageNames.CSharp) + { + { SpaceBetweenParentheses, SpaceBetweenParentheses.DefaultValue.WithFlagValue( SpacePlacementWithinParentheses.ControlFlowStatements, true) }, + }; + await AssertFormatAsync(expected, code, changedOptionSet: optionSet); } @@ -7267,7 +7265,7 @@ public void Method() var options = new OptionsCollection(LanguageNames.CSharp) { - { CSharpFormattingOptions2.NewLinesForBracesInControlBlocks, false } + { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ControlBlocks, false) } }; await AssertFormatAsync(expected, code, changedOptionSet: options); @@ -7306,7 +7304,7 @@ public void Method() var options = new OptionsCollection(LanguageNames.CSharp) { - { CSharpFormattingOptions2.NewLinesForBracesInControlBlocks, false } + { NewLineBeforeOpenBrace , NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ControlBlocks, false) } }; await AssertFormatAsync(expected, code, changedOptionSet: options); @@ -8484,7 +8482,7 @@ public async Task SwitchSectionHonorsNewLineForBracesinControlBlockOption_NonDef { var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - { CSharpFormattingOptions2.NewLinesForBracesInControlBlocks, false } + { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ControlBlocks, false) } }; var code = @"class Program { @@ -8627,7 +8625,7 @@ public async Task NewLinesForBracesInPropertiesTest() { var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - { CSharpFormattingOptions2.NewLinesForBracesInProperties, false } + { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.Properties, false) }, }; await AssertFormatAsync(@"class Class2 { @@ -8665,7 +8663,7 @@ public async Task NewLinesForBracesInAccessorsTest() { var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - { CSharpFormattingOptions2.NewLinesForBracesInAccessors, false } + { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.Accessors, false) }, }; await AssertFormatAsync(@"class Class2 { @@ -8703,8 +8701,9 @@ public async Task NewLinesForBracesInPropertiesAndAccessorsTest() { var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - { CSharpFormattingOptions2.NewLinesForBracesInProperties, false }, - { CSharpFormattingOptions2.NewLinesForBracesInAccessors, false } + { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue + .WithFlagValue(NewLineBeforeOpenBracePlacement.Properties, false) + .WithFlagValue(NewLineBeforeOpenBracePlacement.Accessors, false)}, }; await AssertFormatAsync(@"class Class2 { @@ -9755,7 +9754,7 @@ public async Task NewLinesForBraces_SwitchExpression_NonDefault() { var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - { NewLinesForBracesInObjectCollectionArrayInitializers, false }, + { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ObjectCollectionArrayInitializers, false) }, }; await AssertFormatAsync( @" @@ -9815,7 +9814,7 @@ public async Task NewLinesForBraces_RecordWithInitializer_NonDefault() { var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - { NewLinesForBracesInObjectCollectionArrayInitializers, false }, + { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ObjectCollectionArrayInitializers, false) }, }; await AssertFormatAsync( @" @@ -9925,7 +9924,7 @@ public async Task NewLinesForBraces_PropertyPatternClauses_NonDefault() { var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - { NewLinesForBracesInObjectCollectionArrayInitializers, false }, + { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ObjectCollectionArrayInitializers, false) }, }; await AssertFormatAsync( @" @@ -9961,7 +9960,7 @@ public async Task NewLinesForBraces_PropertyPatternClauses_SingleLine(bool optio { var changingOptions = new OptionsCollection(LanguageNames.CSharp) { - { NewLinesForBracesInObjectCollectionArrayInitializers, option }, + { NewLineBeforeOpenBrace, NewLineBeforeOpenBrace.DefaultValue.WithFlagValue(NewLineBeforeOpenBracePlacement.ObjectCollectionArrayInitializers, option) }, }; var code = @" class A diff --git a/src/Workspaces/CSharpTest/Formatting/FormattingTests_Patterns.cs b/src/Workspaces/CSharpTest/Formatting/FormattingTests_Patterns.cs index aa67130b0cf0e..913c10f5a0be1 100644 --- a/src/Workspaces/CSharpTest/Formatting/FormattingTests_Patterns.cs +++ b/src/Workspaces/CSharpTest/Formatting/FormattingTests_Patterns.cs @@ -162,7 +162,7 @@ bool Method(int value) var changingOptions = new OptionsCollection(LanguageNames.CSharp) { { CSharpFormattingOptions2.SpacingAroundBinaryOperator, spacing }, - { CSharpFormattingOptions2.SpaceWithinExpressionParentheses, spaceWithinExpressionParentheses }, + { CSharpFormattingOptions2.SpaceBetweenParentheses, CSharpFormattingOptions2.SpaceBetweenParentheses.DefaultValue.WithFlagValue(SpacePlacementWithinParentheses.Expressions, spaceWithinExpressionParentheses) }, }; await AssertFormatAsync(expected, content, changedOptionSet: changingOptions); } @@ -309,7 +309,7 @@ bool Method(int value) var changingOptions = new OptionsCollection(LanguageNames.CSharp) { { CSharpFormattingOptions2.SpacingAroundBinaryOperator, spacing }, - { CSharpFormattingOptions2.SpaceWithinExpressionParentheses, spaceWithinExpressionParentheses }, + { CSharpFormattingOptions2.SpaceBetweenParentheses, CSharpFormattingOptions2.SpaceBetweenParentheses.DefaultValue.WithFlagValue(SpacePlacementWithinParentheses.Expressions, spaceWithinExpressionParentheses) }, }; await AssertFormatAsync(expected, content, changedOptionSet: changingOptions); } diff --git a/src/Workspaces/Core/MSBuild/MSBuild/MSBuildProjectLoader.Worker.cs b/src/Workspaces/Core/MSBuild/MSBuild/MSBuildProjectLoader.Worker.cs index a83f54039c58e..32b6db85b655d 100644 --- a/src/Workspaces/Core/MSBuild/MSBuild/MSBuildProjectLoader.Worker.cs +++ b/src/Workspaces/Core/MSBuild/MSBuild/MSBuildProjectLoader.Worker.cs @@ -24,7 +24,7 @@ public partial class MSBuildProjectLoader { private partial class Worker { - private readonly HostWorkspaceServices _workspaceServices; + private readonly SolutionServices _solutionServices; private readonly DiagnosticReporter _diagnosticReporter; private readonly PathResolver _pathResolver; private readonly ProjectFileLoaderRegistry _projectFileLoaderRegistry; @@ -72,7 +72,7 @@ private partial class Worker private readonly Dictionary> _pathToDiscoveredProjectInfosMap; public Worker( - HostWorkspaceServices services, + SolutionServices services, DiagnosticReporter diagnosticReporter, PathResolver pathResolver, ProjectFileLoaderRegistry projectFileLoaderRegistry, @@ -86,7 +86,7 @@ public Worker( DiagnosticReportingOptions discoveredProjectOptions, bool preferMetadataForReferencesOfDiscoveredProjects) { - _workspaceServices = services; + _solutionServices = services; _diagnosticReporter = diagnosticReporter; _pathResolver = pathResolver; _projectFileLoaderRegistry = projectFileLoaderRegistry; @@ -452,7 +452,7 @@ private ImmutableArray CreateDocumentInfos(IReadOnlyList documents, private TLanguageService? GetLanguageService(string languageName) where TLanguageService : ILanguageService - => _workspaceServices + => _solutionServices .GetLanguageServices(languageName) .GetService(); private TWorkspaceService? GetWorkspaceService() where TWorkspaceService : IWorkspaceService - => _workspaceServices + => _solutionServices .GetService(); } } diff --git a/src/Workspaces/Core/MSBuild/MSBuild/MSBuildProjectLoader.Worker_ResolveReferences.cs b/src/Workspaces/Core/MSBuild/MSBuild/MSBuildProjectLoader.Worker_ResolveReferences.cs index a4b7d2ddfa68f..6a1cbd3d44c9b 100644 --- a/src/Workspaces/Core/MSBuild/MSBuild/MSBuildProjectLoader.Worker_ResolveReferences.cs +++ b/src/Workspaces/Core/MSBuild/MSBuild/MSBuildProjectLoader.Worker_ResolveReferences.cs @@ -188,7 +188,7 @@ private async Task ResolveReferencesAsync(ProjectId id, Proj // First, gather all of the metadata references from the command-line arguments. var resolvedMetadataReferences = commandLineArgs.ResolveMetadataReferences( new WorkspaceMetadataFileReferenceResolver( - metadataService: _workspaceServices.GetRequiredService(), + metadataService: _solutionServices.GetRequiredService(), pathResolver: new RelativePathResolver(commandLineArgs.ReferencePaths, commandLineArgs.BaseDirectory))); var builder = new ResolvedReferencesBuilder(resolvedMetadataReferences); diff --git a/src/Workspaces/Core/MSBuild/MSBuild/MSBuildProjectLoader.cs b/src/Workspaces/Core/MSBuild/MSBuild/MSBuildProjectLoader.cs index 2f323d373ff82..52c2c65450278 100644 --- a/src/Workspaces/Core/MSBuild/MSBuild/MSBuildProjectLoader.cs +++ b/src/Workspaces/Core/MSBuild/MSBuild/MSBuildProjectLoader.cs @@ -20,8 +20,8 @@ namespace Microsoft.CodeAnalysis.MSBuild /// public partial class MSBuildProjectLoader { - // the workspace that the projects and solutions are intended to be loaded into. - private readonly HostWorkspaceServices _workspaceServices; + // the services for the projects and solutions are intended to be loaded into. + private readonly SolutionServices _solutionServices; private readonly DiagnosticReporter _diagnosticReporter; private readonly PathResolver _pathResolver; @@ -31,15 +31,15 @@ public partial class MSBuildProjectLoader private readonly NonReentrantLock _dataGuard = new(); internal MSBuildProjectLoader( - HostWorkspaceServices workspaceServices, + SolutionServices solutionServices, DiagnosticReporter diagnosticReporter, ProjectFileLoaderRegistry? projectFileLoaderRegistry, ImmutableDictionary? properties) { - _workspaceServices = workspaceServices; + _solutionServices = solutionServices; _diagnosticReporter = diagnosticReporter; _pathResolver = new PathResolver(_diagnosticReporter); - _projectFileLoaderRegistry = projectFileLoaderRegistry ?? new ProjectFileLoaderRegistry(workspaceServices, _diagnosticReporter); + _projectFileLoaderRegistry = projectFileLoaderRegistry ?? new ProjectFileLoaderRegistry(solutionServices, _diagnosticReporter); Properties = ImmutableDictionary.Create(StringComparer.OrdinalIgnoreCase); @@ -56,7 +56,7 @@ internal MSBuildProjectLoader( /// An optional dictionary of additional MSBuild properties and values to use when loading projects. /// These are the same properties that are passed to msbuild via the /property:<n>=<v> command line argument. public MSBuildProjectLoader(Workspace workspace, ImmutableDictionary? properties = null) - : this(workspace.Services, new DiagnosticReporter(workspace), projectFileLoaderRegistry: null, properties) + : this(workspace.Services.SolutionServices, new DiagnosticReporter(workspace), projectFileLoaderRegistry: null, properties) { } @@ -200,7 +200,7 @@ public async Task LoadSolutionInfoAsync( var buildManager = new ProjectBuildManager(Properties, msbuildLogger); var worker = new Worker( - _workspaceServices, + _solutionServices, _diagnosticReporter, _pathResolver, _projectFileLoaderRegistry, @@ -259,7 +259,7 @@ public async Task> LoadProjectInfoAsync( var buildManager = new ProjectBuildManager(Properties, msbuildLogger); var worker = new Worker( - _workspaceServices, + _solutionServices, _diagnosticReporter, _pathResolver, _projectFileLoaderRegistry, diff --git a/src/Workspaces/Core/MSBuild/MSBuild/MSBuildWorkspace.cs b/src/Workspaces/Core/MSBuild/MSBuild/MSBuildWorkspace.cs index c480a89edb51d..b3a60c92e978a 100644 --- a/src/Workspaces/Core/MSBuild/MSBuild/MSBuildWorkspace.cs +++ b/src/Workspaces/Core/MSBuild/MSBuild/MSBuildWorkspace.cs @@ -41,8 +41,8 @@ private MSBuildWorkspace( : base(hostServices, WorkspaceKind.MSBuild) { _reporter = new DiagnosticReporter(this); - _projectFileLoaderRegistry = new ProjectFileLoaderRegistry(Services, _reporter); - _loader = new MSBuildProjectLoader(Services, _reporter, _projectFileLoaderRegistry, properties); + _projectFileLoaderRegistry = new ProjectFileLoaderRegistry(Services.SolutionServices, _reporter); + _loader = new MSBuildProjectLoader(Services.SolutionServices, _reporter, _projectFileLoaderRegistry, properties); } /// diff --git a/src/Workspaces/Core/MSBuild/MSBuild/ProjectFile/ProjectFileLoader.cs b/src/Workspaces/Core/MSBuild/MSBuild/ProjectFile/ProjectFileLoader.cs index d6a0a6fe61c90..f12fe97a64d09 100644 --- a/src/Workspaces/Core/MSBuild/MSBuild/ProjectFile/ProjectFileLoader.cs +++ b/src/Workspaces/Core/MSBuild/MSBuild/ProjectFile/ProjectFileLoader.cs @@ -34,9 +34,9 @@ public async Task LoadProjectFileAsync(string path, ProjectBuildMa return this.CreateProjectFile(project, buildManager, log); } - public static IProjectFileLoader GetLoaderForProjectFileExtension(HostWorkspaceServices workspaceServices, string extension) + public static IProjectFileLoader GetLoaderForProjectFileExtension(SolutionServices solutionServices, string extension) { - return workspaceServices.FindLanguageServices( + return solutionServices.FindLanguageServices( d => d.GetEnumerableMetadata("ProjectFileExtension").Any(e => string.Equals(e, extension, StringComparison.OrdinalIgnoreCase))) .FirstOrDefault(); } diff --git a/src/Workspaces/Core/MSBuild/MSBuild/ProjectFile/ProjectFileLoaderRegistry.cs b/src/Workspaces/Core/MSBuild/MSBuild/ProjectFile/ProjectFileLoaderRegistry.cs index 96e552c66a6d9..90d1c51fc64fd 100644 --- a/src/Workspaces/Core/MSBuild/MSBuild/ProjectFile/ProjectFileLoaderRegistry.cs +++ b/src/Workspaces/Core/MSBuild/MSBuild/ProjectFile/ProjectFileLoaderRegistry.cs @@ -13,14 +13,14 @@ namespace Microsoft.CodeAnalysis.MSBuild { internal class ProjectFileLoaderRegistry { - private readonly HostWorkspaceServices _workspaceServices; + private readonly SolutionServices _solutionServices; private readonly DiagnosticReporter _diagnosticReporter; private readonly Dictionary _extensionToLanguageMap; private readonly NonReentrantLock _dataGuard; - public ProjectFileLoaderRegistry(HostWorkspaceServices workspaceServices, DiagnosticReporter diagnosticReporter) + public ProjectFileLoaderRegistry(SolutionServices solutionServices, DiagnosticReporter diagnosticReporter) { - _workspaceServices = workspaceServices; + _solutionServices = solutionServices; _diagnosticReporter = diagnosticReporter; _extensionToLanguageMap = new Dictionary(StringComparer.OrdinalIgnoreCase); _dataGuard = new NonReentrantLock(); @@ -61,9 +61,9 @@ public bool TryGetLoaderFromProjectPath(string? projectFilePath, DiagnosticRepor if (_extensionToLanguageMap.TryGetValue(extension, out var language)) { - if (_workspaceServices.SupportedLanguages.Contains(language)) + if (_solutionServices.SupportedLanguages.Contains(language)) { - loader = _workspaceServices.GetLanguageServices(language).GetService(); + loader = _solutionServices.GetLanguageServices(language).GetService(); } else { @@ -74,7 +74,7 @@ public bool TryGetLoaderFromProjectPath(string? projectFilePath, DiagnosticRepor } else { - loader = ProjectFileLoader.GetLoaderForProjectFileExtension(_workspaceServices, extension); + loader = ProjectFileLoader.GetLoaderForProjectFileExtension(_solutionServices, extension); if (loader == null) { @@ -89,7 +89,7 @@ public bool TryGetLoaderFromProjectPath(string? projectFilePath, DiagnosticRepor language = loader.Language; // check for command line parser existing... if not then error. - var commandLineParser = _workspaceServices + var commandLineParser = _solutionServices .GetLanguageServices(language) .GetService(); diff --git a/src/Workspaces/Core/MSBuild/Microsoft.CodeAnalysis.Workspaces.MSBuild.csproj b/src/Workspaces/Core/MSBuild/Microsoft.CodeAnalysis.Workspaces.MSBuild.csproj index a65fc35f1c3bb..642f0d84e7b61 100644 --- a/src/Workspaces/Core/MSBuild/Microsoft.CodeAnalysis.Workspaces.MSBuild.csproj +++ b/src/Workspaces/Core/MSBuild/Microsoft.CodeAnalysis.Workspaces.MSBuild.csproj @@ -39,6 +39,7 @@ + diff --git a/src/Workspaces/Core/Portable/Classification/SyntaxClassification/ISyntaxClassifier.cs b/src/Workspaces/Core/Portable/Classification/SyntaxClassification/ISyntaxClassifier.cs index 100804f575d8a..5c0b72ac6acb7 100644 --- a/src/Workspaces/Core/Portable/Classification/SyntaxClassification/ISyntaxClassifier.cs +++ b/src/Workspaces/Core/Portable/Classification/SyntaxClassification/ISyntaxClassifier.cs @@ -4,11 +4,7 @@ using System; using System.Collections.Immutable; -using System.Composition; using System.Threading; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Options.Providers; using Microsoft.CodeAnalysis.PooledObjects; namespace Microsoft.CodeAnalysis.Classification.Classifiers diff --git a/src/Workspaces/Core/Portable/CodeGeneration/AbstractCodeGenerationService.cs b/src/Workspaces/Core/Portable/CodeGeneration/AbstractCodeGenerationService.cs index 4eba9dcc7b8dc..73a543296f40f 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/AbstractCodeGenerationService.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/AbstractCodeGenerationService.cs @@ -13,6 +13,7 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.LanguageService; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Simplification; @@ -32,7 +33,7 @@ protected AbstractCodeGenerationService( } public abstract CodeGenerationOptions DefaultOptions { get; } - public abstract CodeGenerationOptions GetCodeGenerationOptions(AnalyzerConfigOptions info, CodeGenerationOptions? fallbackOptions); + public abstract CodeGenerationOptions GetCodeGenerationOptions(IOptionsReader options, CodeGenerationOptions? fallbackOptions); #region ICodeGenerationService diff --git a/src/Workspaces/Core/Portable/CodeGeneration/ICodeGenerationService.cs b/src/Workspaces/Core/Portable/CodeGeneration/ICodeGenerationService.cs index 48f8f47f09cdc..cb06a88900a2b 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/ICodeGenerationService.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/ICodeGenerationService.cs @@ -14,7 +14,7 @@ namespace Microsoft.CodeAnalysis.CodeGeneration internal interface ICodeGenerationService : ILanguageService { CodeGenerationOptions DefaultOptions { get; } - CodeGenerationOptions GetCodeGenerationOptions(AnalyzerConfigOptions options, CodeGenerationOptions? fallbackOptions); + CodeGenerationOptions GetCodeGenerationOptions(IOptionsReader options, CodeGenerationOptions? fallbackOptions); /// /// Returns a newly created event declaration node from the provided event. diff --git a/src/Workspaces/Core/Portable/CodeStyle/CodeStyleOption.cs b/src/Workspaces/Core/Portable/CodeStyle/CodeStyleOption.cs index 9e64c628de069..34fd3a6d07e99 100644 --- a/src/Workspaces/Core/Portable/CodeStyle/CodeStyleOption.cs +++ b/src/Workspaces/Core/Portable/CodeStyle/CodeStyleOption.cs @@ -40,6 +40,7 @@ public T Value ICodeStyleOption ICodeStyleOption.WithNotification(NotificationOption2 notification) => new CodeStyleOption(Value, (NotificationOption)notification); ICodeStyleOption ICodeStyleOption.AsCodeStyleOption() => this is TCodeStyleOption ? this : _codeStyleOptionImpl; + ICodeStyleOption ICodeStyleOption.AsInternalCodeStyleOption() => _codeStyleOptionImpl; ICodeStyleOption ICodeStyleOption.AsPublicCodeStyleOption() => this; public NotificationOption Notification diff --git a/src/Workspaces/Core/Portable/CodeStyle/CodeStyleOptionsProvider.cs b/src/Workspaces/Core/Portable/CodeStyle/CodeStyleOptionsProvider.cs deleted file mode 100644 index c79398a052b5d..0000000000000 --- a/src/Workspaces/Core/Portable/CodeStyle/CodeStyleOptionsProvider.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections.Immutable; -using System.Composition; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Options.Providers; - -namespace Microsoft.CodeAnalysis.CodeStyle -{ - [ExportSolutionOptionProvider, Shared] - internal sealed class SolutionCodeStyleOptionsProvider : IOptionProvider - { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public SolutionCodeStyleOptionsProvider() - { - } - - public ImmutableArray Options { get; } = CodeStyleOptions2.AllOptions.As(); - } -} diff --git a/src/Workspaces/Core/Portable/CodeStyle/ICodeStyleService.cs b/src/Workspaces/Core/Portable/CodeStyle/ICodeStyleService.cs index 2cddece71f715..d88e032c78954 100644 --- a/src/Workspaces/Core/Portable/CodeStyle/ICodeStyleService.cs +++ b/src/Workspaces/Core/Portable/CodeStyle/ICodeStyleService.cs @@ -2,14 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Collections.Generic; -using System.Text; using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.CodeStyle; internal interface ICodeStyleService : ILanguageService { IdeCodeStyleOptions DefaultOptions { get; } + IdeCodeStyleOptions GetIdeCodeStyleOptions(IOptionsReader options, IdeCodeStyleOptions? fallbackOptions); } diff --git a/src/Workspaces/Core/Portable/Editing/DeclarationModifiers.cs b/src/Workspaces/Core/Portable/Editing/DeclarationModifiers.cs index a4bd00effed3a..34454e448854a 100644 --- a/src/Workspaces/Core/Portable/Editing/DeclarationModifiers.cs +++ b/src/Workspaces/Core/Portable/Editing/DeclarationModifiers.cs @@ -73,11 +73,12 @@ IMethodSymbol or var field = symbol as IFieldSymbol; var property = symbol as IPropertySymbol; var method = symbol as IMethodSymbol; + var type = symbol as INamedTypeSymbol; return new DeclarationModifiers( isStatic: symbol.IsStatic, isAbstract: symbol.IsAbstract, - isReadOnly: field?.IsReadOnly == true || property?.IsReadOnly == true, + isReadOnly: field?.IsReadOnly == true || property?.IsReadOnly == true || type?.IsReadOnly == true || method?.IsReadOnly == true, isVirtual: symbol.IsVirtual, isOverride: symbol.IsOverride, isSealed: symbol.IsSealed, diff --git a/src/Workspaces/Core/Portable/Editing/GenerationOptionsProvider.cs b/src/Workspaces/Core/Portable/Editing/GenerationOptionsProvider.cs deleted file mode 100644 index 566b90519a29f..0000000000000 --- a/src/Workspaces/Core/Portable/Editing/GenerationOptionsProvider.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections.Immutable; -using System.Composition; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Options.Providers; - -namespace Microsoft.CodeAnalysis.Editing -{ - [ExportSolutionOptionProvider, Shared] - internal class GenerationOptionsProvider : IOptionProvider - { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public GenerationOptionsProvider() - { - } - - public ImmutableArray Options { get; } = GenerationOptions.AllOptions.As(); - } -} diff --git a/src/Workspaces/Core/Portable/ExternalAccess/UnitTesting/Api/IUnitTestingIncrementalAnalyzerImplementation.cs b/src/Workspaces/Core/Portable/ExternalAccess/UnitTesting/Api/IUnitTestingIncrementalAnalyzerImplementation.cs index 701cc62a1bfbc..9b9b23b2df17c 100644 --- a/src/Workspaces/Core/Portable/ExternalAccess/UnitTesting/Api/IUnitTestingIncrementalAnalyzerImplementation.cs +++ b/src/Workspaces/Core/Portable/ExternalAccess/UnitTesting/Api/IUnitTestingIncrementalAnalyzerImplementation.cs @@ -21,8 +21,5 @@ internal interface IUnitTestingIncrementalAnalyzerImplementation Task AnalyzeProjectAsync(Project project, bool semanticsChanged, UnitTestingInvocationReasonsWrapper reasons, CancellationToken cancellationToken); void RemoveDocument(DocumentId documentId); void RemoveProject(ProjectId projectId); - - [Obsolete] - bool NeedsReanalysisOnOptionChanged(object sender, UnitTestingOptionChangedEventArgsWrapper e); } } diff --git a/src/Workspaces/Core/Portable/ExternalAccess/UnitTesting/Api/UnitTestingOptionChangedEventArgsWrapper.cs b/src/Workspaces/Core/Portable/ExternalAccess/UnitTesting/Api/UnitTestingOptionChangedEventArgsWrapper.cs deleted file mode 100644 index a19019f6a2dc1..0000000000000 --- a/src/Workspaces/Core/Portable/ExternalAccess/UnitTesting/Api/UnitTestingOptionChangedEventArgsWrapper.cs +++ /dev/null @@ -1,18 +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 Microsoft.CodeAnalysis.Options; - -namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.Api -{ - [Obsolete] - internal readonly struct UnitTestingOptionChangedEventArgsWrapper - { - internal OptionChangedEventArgs UnderlyingObject { get; } - - public UnitTestingOptionChangedEventArgsWrapper(OptionChangedEventArgs underlyingObject) - => UnderlyingObject = underlyingObject ?? throw new ArgumentNullException(nameof(underlyingObject)); - } -} diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder.cs index 2fe08d5457b4c..f299b9b02e46c 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder.cs @@ -42,9 +42,9 @@ internal static partial class DependentTypeFinder private static readonly Func s_isInMetadata = static loc => loc.IsInMetadata; private static readonly Func s_isInSource = static loc => loc.IsInSource; - private static readonly Func s_isInterface = t => t?.TypeKind == TypeKind.Interface; - private static readonly Func s_isNonSealedClass = t => t?.TypeKind == TypeKind.Class && !t.IsSealed; - private static readonly Func s_isInterfaceOrNonSealedClass = t => s_isInterface(t) || s_isNonSealedClass(t); + private static readonly Func s_isInterface = static t => t is { TypeKind: TypeKind.Interface }; + private static readonly Func s_isNonSealedClass = static t => t is { TypeKind: TypeKind.Class, IsSealed: false }; + private static readonly Func s_isInterfaceOrNonSealedClass = static t => s_isInterface(t) || s_isNonSealedClass(t); private static readonly ObjectPool> s_symbolSetPool = PooledHashSet.CreatePool(SymbolEquivalenceComparer.Instance); @@ -112,6 +112,11 @@ private static async Task> DescendInheritanceTr // Same as above, but contains source types as well. using var _3 = GetSymbolSet(out var currentSourceAndMetadataTypes); + // The set of PEReferences we've examined. We only need to examine a reference once when we encounter it + // while walking projects. PEReferences cannot reference source symbols, so the results from them cannot + // change as we examine further projects. + using var _4 = PooledHashSet.GetInstance(out var seenPEReferences); + currentSourceAndMetadataTypes.Add(type); if (searchInMetadata) currentMetadataTypes.Add(type); @@ -128,88 +133,240 @@ private static async Task> DescendInheritanceTr cancellationToken.ThrowIfCancellationRequested(); if (project.SupportsCompilation) + await DescendInheritanceTreeInProjectAsync(project).ConfigureAwait(false); + } + + return result.ToImmutableArray(); + + async Task DescendInheritanceTreeInProjectAsync(Project project) + { + cancellationToken.ThrowIfCancellationRequested(); + + Debug.Assert(project.SupportsCompilation); + + // First see what derived metadata types we might find in this project. This is only necessary if we + // started with a metadata type (i.e. a source type could not have a descendant type found in metadata, + // but a metadata type could have descendant types in source and metadata). + if (searchInMetadata) + { + using var _ = GetSymbolSet(out var tempBuffer); + + await AddDescendantMetadataTypesInProjectAsync(tempBuffer, project).ConfigureAwait(false); + + // Add all the matches we found to the result set. + AssertContents(tempBuffer, assert: s_isInMetadata, "Found type was not from metadata"); + AddRange(tempBuffer, result); + + // Now, if we're doing a transitive search, add these found types to the 'current' sets we're + // searching for more results for. These will then be used when searching for more types in the next + // project (which our caller controls). + if (transitive) + { + AddRange(tempBuffer, currentMetadataTypes, shouldContinueSearching); + AddRange(tempBuffer, currentSourceAndMetadataTypes, shouldContinueSearching); + } + } + { - await DescendInheritanceTreeInProjectAsync( - searchInMetadata, result, - currentMetadataTypes, currentSourceAndMetadataTypes, - project, - typeMatches, - shouldContinueSearching, - transitive, cancellationToken).ConfigureAwait(false); + using var _ = GetSymbolSet(out var tempBuffer); + + // Now search the project and see what source types we can find. + await AddDescendantSourceTypesInProjectAsync(tempBuffer, project).ConfigureAwait(false); + + // Add all the matches we found to the result set. + AssertContents(tempBuffer, assert: s_isInSource, "Found type was not from source"); + AddRange(tempBuffer, result); + + // Now, if we're doing a transitive search, add these types to the currentSourceAndMetadataTypes + // set. These will then be used when searching for more types in the next project (which our caller + // controls). We don't have to add this to currentMetadataTypes since these will all be + // source types. + if (transitive) + AddRange(tempBuffer, currentSourceAndMetadataTypes, shouldContinueSearching); } } - return result.ToImmutableArray(); - } + async Task AddDescendantSourceTypesInProjectAsync(SymbolSet result, Project project) + { + cancellationToken.ThrowIfCancellationRequested(); - private static async Task DescendInheritanceTreeInProjectAsync( - bool searchInMetadata, - SymbolSet result, - SymbolSet currentMetadataTypes, - SymbolSet currentSourceAndMetadataTypes, - Project project, - Func typeMatches, - Func shouldContinueSearching, - bool transitive, - CancellationToken cancellationToken) - { - cancellationToken.ThrowIfCancellationRequested(); + // We're going to be sweeping over this project over and over until we reach a + // fixed point. In order to limit GC and excess work, we cache all the semantic + // models and DeclaredSymbolInfo for the documents we look at. + // Because we're only processing a project at a time, this is not an issue. + var cachedModels = new ConcurrentSet(); - Debug.Assert(project.SupportsCompilation); + using var _1 = GetSymbolSet(out var typesToSearchFor); + using var _2 = GetSymbolSet(out var tempBuffer); - // First see what derived metadata types we might find in this project. This is only necessary if we - // started with a metadata type (i.e. a source type could not have a descendant type found in metadata, - // but a metadata type could have descendant types in source and metadata). - if (searchInMetadata) + typesToSearchFor.AddAll(currentSourceAndMetadataTypes); + + var projectIndex = await ProjectIndex.GetIndexAsync(project, cancellationToken).ConfigureAwait(false); + + // As long as there are new types to search for, keep looping. + while (typesToSearchFor.Count > 0) + { + foreach (var type in typesToSearchFor) + { + cancellationToken.ThrowIfCancellationRequested(); + + switch (type.SpecialType) + { + case SpecialType.System_Object: + await AddMatchingTypesAsync( + projectIndex.ClassesAndRecordsThatMayDeriveFromSystemObject, + tempBuffer, + predicateOpt: n => n.BaseType?.SpecialType == SpecialType.System_Object).ConfigureAwait(false); + break; + case SpecialType.System_ValueType: + await AddMatchingTypesAsync( + projectIndex.ValueTypes, tempBuffer, predicateOpt: null).ConfigureAwait(false); + break; + case SpecialType.System_Enum: + await AddMatchingTypesAsync( + projectIndex.Enums, tempBuffer, predicateOpt: null).ConfigureAwait(false); + break; + case SpecialType.System_MulticastDelegate: + await AddMatchingTypesAsync( + projectIndex.Delegates, tempBuffer, predicateOpt: null).ConfigureAwait(false); + break; + } + + await AddSourceTypesThatDeriveFromNameAsync(tempBuffer, type.Name).ConfigureAwait(false); + } + + PropagateTemporaryResults( + result, typesToSearchFor, tempBuffer, transitive, shouldContinueSearching); + } + + async Task AddMatchingTypesAsync( + MultiDictionary documentToInfos, + SymbolSet result, + Func? predicateOpt) + { + foreach (var (document, infos) in documentToInfos) + { + cancellationToken.ThrowIfCancellationRequested(); + + Debug.Assert(infos.Count > 0); + var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); + cachedModels.Add(semanticModel); + + foreach (var info in infos) + { + cancellationToken.ThrowIfCancellationRequested(); + + var resolvedSymbol = info.TryResolve(semanticModel, cancellationToken); + if (resolvedSymbol is INamedTypeSymbol namedType) + { + if (predicateOpt == null || + predicateOpt(namedType)) + { + result.Add(namedType); + } + } + } + } + } + + async Task AddSourceTypesThatDeriveFromNameAsync(SymbolSet result, string name) + { + foreach (var (document, info) in projectIndex.NamedTypes[name]) + { + cancellationToken.ThrowIfCancellationRequested(); + + var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); + cachedModels.Add(semanticModel); + + var resolvedType = info.TryResolve(semanticModel, cancellationToken); + if (resolvedType is INamedTypeSymbol namedType && + typeMatches(namedType, typesToSearchFor)) + { + result.Add(namedType); + } + } + } + } + + async Task AddDescendantMetadataTypesInProjectAsync(SymbolSet result, Project project) { - using var _ = GetSymbolSet(out var tempBuffer); - - await AddDescendantMetadataTypesInProjectAsync( - currentMetadataTypes, - result: tempBuffer, - project, - typeMatches, - shouldContinueSearching, - transitive, - cancellationToken).ConfigureAwait(false); - - // Add all the matches we found to the result set. - AssertContents(tempBuffer, assert: s_isInMetadata, "Found type was not from metadata"); - AddRange(tempBuffer, result); - - // Now, if we're doing a transitive search, add these found types to the 'current' sets we're - // searching for more results for. These will then be used when searching for more types in the next - // project (which our caller controls). - if (transitive) + Debug.Assert(project.SupportsCompilation); + + if (currentMetadataTypes.Count == 0) + return; + + var compilation = await project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false); + + using var _1 = GetSymbolSet(out var typesToSearchFor); + using var _2 = GetSymbolSet(out var tempBuffer); + + typesToSearchFor.AddAll(currentMetadataTypes); + + // As long as there are new types to search for, keep looping. + while (typesToSearchFor.Count > 0) { - AddRange(tempBuffer, currentMetadataTypes, shouldContinueSearching); - AddRange(tempBuffer, currentSourceAndMetadataTypes, shouldContinueSearching); + foreach (var reference in compilation.References) + { + if (reference is not PortableExecutableReference peReference) + continue; + + // Don't look inside this reference if we already looked inside it in another project. + if (seenPEReferences.Contains(peReference)) + continue; + + cancellationToken.ThrowIfCancellationRequested(); + + await AddMatchingMetadataTypesInMetadataReferenceAsync( + typesToSearchFor, project, compilation, peReference, tempBuffer).ConfigureAwait(false); + } + + PropagateTemporaryResults( + result, typesToSearchFor, tempBuffer, transitive, shouldContinueSearching); } + + // Mark all these references as having been seen. We don't need to examine it in future projects. + seenPEReferences.AddRange(compilation.References.OfType()); } + async Task AddMatchingMetadataTypesInMetadataReferenceAsync( + SymbolSet metadataTypes, + Project project, + Compilation compilation, + PortableExecutableReference reference, + SymbolSet result) { - using var _ = GetSymbolSet(out var tempBuffer); - - // Now search the project and see what source types we can find. - await AddDescendantSourceTypesInProjectAsync( - currentSourceAndMetadataTypes, - result: tempBuffer, - project, - typeMatches, - shouldContinueSearching, - transitive, - cancellationToken).ConfigureAwait(false); - - // Add all the matches we found to the result set. - AssertContents(tempBuffer, assert: s_isInSource, "Found type was not from source"); - AddRange(tempBuffer, result); - - // Now, if we're doing a transitive search, add these types to the currentSourceAndMetadataTypes - // set. These will then be used when searching for more types in the next project (which our caller - // controls). We don't have to add this to currentMetadataTypes since these will all be - // source types. - if (transitive) - AddRange(tempBuffer, currentSourceAndMetadataTypes, shouldContinueSearching); + cancellationToken.ThrowIfCancellationRequested(); + + // We store an index in SymbolTreeInfo of the *simple* metadata type name to the names of the all the types + // that either immediately derive or implement that type. Because the mapping is from the simple name we + // might get false positives. But that's fine as we still use 'tpeMatches' to make sure the match is + // correct. + var symbolTreeInfo = await SymbolTreeInfo.GetInfoForMetadataReferenceAsync( + project.Solution, reference, checksum: null, cancellationToken).ConfigureAwait(false); + + Contract.ThrowIfNull(symbolTreeInfo); + + // For each type we care about, see if we can find any derived types + // in this index. + foreach (var metadataType in metadataTypes) + { + cancellationToken.ThrowIfCancellationRequested(); + + var baseTypeName = metadataType.Name; + + // For each derived type we find, see if we can map that back + // to an actual symbol. Then check if that symbol actually fits + // our criteria. + foreach (var derivedType in symbolTreeInfo.GetDerivedMetadataTypes(baseTypeName, compilation, cancellationToken)) + { + if (derivedType != null && + derivedType.Locations.Any(s_isInMetadata) && + typeMatches(derivedType, metadataTypes)) + { + result.Add(derivedType); + } + } + } } } @@ -354,91 +511,6 @@ private static ImmutableArray GetProjectsToExamineWorker( .ToImmutableArray(); } - private static async Task AddDescendantMetadataTypesInProjectAsync( - SymbolSet currentMetadataTypes, - SymbolSet result, - Project project, - Func typeMatches, - Func shouldContinueSearching, - bool transitive, - CancellationToken cancellationToken) - { - Debug.Assert(project.SupportsCompilation); - - if (currentMetadataTypes.Count == 0) - return; - - var compilation = await project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false); - - using var _1 = GetSymbolSet(out var typesToSearchFor); - using var _2 = GetSymbolSet(out var tempBuffer); - - typesToSearchFor.AddAll(currentMetadataTypes); - - // As long as there are new types to search for, keep looping. - while (typesToSearchFor.Count > 0) - { - foreach (var reference in compilation.References) - { - if (reference is not PortableExecutableReference peReference) - continue; - - cancellationToken.ThrowIfCancellationRequested(); - - await AddMatchingMetadataTypesInMetadataReferenceAsync( - typesToSearchFor, project, typeMatches, - compilation, peReference, tempBuffer, - cancellationToken).ConfigureAwait(false); - } - - PropagateTemporaryResults( - result, typesToSearchFor, tempBuffer, transitive, shouldContinueSearching); - } - } - - private static async Task AddMatchingMetadataTypesInMetadataReferenceAsync( - SymbolSet metadataTypes, - Project project, - Func typeMatches, - Compilation compilation, - PortableExecutableReference reference, - SymbolSet result, - CancellationToken cancellationToken) - { - cancellationToken.ThrowIfCancellationRequested(); - - // We store an index in SymbolTreeInfo of the *simple* metadata type name to the names of the all the types - // that either immediately derive or implement that type. Because the mapping is from the simple name we - // might get false positives. But that's fine as we still use 'tpeMatches' to make sure the match is - // correct. - var symbolTreeInfo = await SymbolTreeInfo.GetInfoForMetadataReferenceAsync( - project.Solution, reference, checksum: null, cancellationToken).ConfigureAwait(false); - - Contract.ThrowIfNull(symbolTreeInfo); - - // For each type we care about, see if we can find any derived types - // in this index. - foreach (var metadataType in metadataTypes) - { - cancellationToken.ThrowIfCancellationRequested(); - - var baseTypeName = metadataType.Name; - - // For each derived type we find, see if we can map that back - // to an actual symbol. Then check if that symbol actually fits - // our criteria. - foreach (var derivedType in symbolTreeInfo.GetDerivedMetadataTypes(baseTypeName, compilation, cancellationToken)) - { - if (derivedType != null && - derivedType.Locations.Any(s_isInMetadata) && - typeMatches(derivedType, metadataTypes)) - { - result.Add(derivedType); - } - } - } - } - private static bool TypeHasBaseTypeInSet(INamedTypeSymbol type, SymbolSet set) { var baseType = type.BaseType?.OriginalDefinition; @@ -456,88 +528,6 @@ private static bool TypeHasInterfaceInSet(INamedTypeSymbol type, SymbolSet set) return false; } - private static async Task AddDescendantSourceTypesInProjectAsync( - SymbolSet currentSourceAndMetadataTypes, - SymbolSet result, - Project project, - Func typeMatches, - Func shouldContinueSearching, - bool transitive, - CancellationToken cancellationToken) - { - cancellationToken.ThrowIfCancellationRequested(); - - // We're going to be sweeping over this project over and over until we reach a - // fixed point. In order to limit GC and excess work, we cache all the semantic - // models and DeclaredSymbolInfo for the documents we look at. - // Because we're only processing a project at a time, this is not an issue. - var cachedModels = new ConcurrentSet(); - - using var _1 = GetSymbolSet(out var typesToSearchFor); - using var _2 = GetSymbolSet(out var tempBuffer); - - typesToSearchFor.AddAll(currentSourceAndMetadataTypes); - - var projectIndex = await ProjectIndex.GetIndexAsync(project, cancellationToken).ConfigureAwait(false); - - // As long as there are new types to search for, keep looping. - while (typesToSearchFor.Count > 0) - { - foreach (var type in typesToSearchFor) - { - cancellationToken.ThrowIfCancellationRequested(); - - switch (type.SpecialType) - { - case SpecialType.System_Object: - await AddMatchingTypesAsync( - cachedModels, - projectIndex.ClassesAndRecordsThatMayDeriveFromSystemObject, - result: tempBuffer, - predicateOpt: n => n.BaseType?.SpecialType == SpecialType.System_Object, - cancellationToken).ConfigureAwait(false); - break; - case SpecialType.System_ValueType: - await AddMatchingTypesAsync( - cachedModels, - projectIndex.ValueTypes, - result: tempBuffer, - predicateOpt: null, - cancellationToken).ConfigureAwait(false); - break; - case SpecialType.System_Enum: - await AddMatchingTypesAsync( - cachedModels, - projectIndex.Enums, - result: tempBuffer, - predicateOpt: null, - cancellationToken).ConfigureAwait(false); - break; - case SpecialType.System_MulticastDelegate: - await AddMatchingTypesAsync( - cachedModels, - projectIndex.Delegates, - result: tempBuffer, - predicateOpt: null, - cancellationToken).ConfigureAwait(false); - break; - } - - await AddSourceTypesThatDeriveFromNameAsync( - typeMatches, - cachedModels, - typesToSearchFor, - projectIndex, - result: tempBuffer, - type.Name, - cancellationToken).ConfigureAwait(false); - } - - PropagateTemporaryResults( - result, typesToSearchFor, tempBuffer, transitive, shouldContinueSearching); - } - } - /// /// Moves all the types in to . If these are types we /// haven't seen before, and the caller says we on them, then add @@ -569,63 +559,6 @@ private static void PropagateTemporaryResults( tempBuffer.Clear(); } - private static async Task AddSourceTypesThatDeriveFromNameAsync( - Func typeMatches, - ConcurrentSet cachedModels, - SymbolSet typesToSearchFor, - ProjectIndex index, - SymbolSet result, - string name, - CancellationToken cancellationToken) - { - foreach (var (document, info) in index.NamedTypes[name]) - { - cancellationToken.ThrowIfCancellationRequested(); - - var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); - cachedModels.Add(semanticModel); - - var resolvedType = info.TryResolve(semanticModel, cancellationToken); - if (resolvedType is INamedTypeSymbol namedType && - typeMatches(namedType, typesToSearchFor)) - { - result.Add(namedType); - } - } - } - - private static async Task AddMatchingTypesAsync( - ConcurrentSet cachedModels, - MultiDictionary documentToInfos, - SymbolSet result, - Func? predicateOpt, - CancellationToken cancellationToken) - { - foreach (var (document, infos) in documentToInfos) - { - cancellationToken.ThrowIfCancellationRequested(); - - Debug.Assert(infos.Count > 0); - var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); - cachedModels.Add(semanticModel); - - foreach (var info in infos) - { - cancellationToken.ThrowIfCancellationRequested(); - - var resolvedSymbol = info.TryResolve(semanticModel, cancellationToken); - if (resolvedSymbol is INamedTypeSymbol namedType) - { - if (predicateOpt == null || - predicateOpt(namedType)) - { - result.Add(namedType); - } - } - } - } - } - public static PooledDisposer> GetSymbolSet(out SymbolSet instance) { var pooledInstance = s_symbolSetPool.Allocate(); diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/AbstractMemberScopedReferenceFinder.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/AbstractMemberScopedReferenceFinder.cs index 9f75c0d24d4d7..08de0d202cb3c 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/AbstractMemberScopedReferenceFinder.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/AbstractMemberScopedReferenceFinder.cs @@ -8,6 +8,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.LanguageService; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; @@ -99,13 +100,22 @@ private ValueTask> FindReferencesInContainerAsync CancellationToken cancellationToken) { var service = state.Document.GetRequiredLanguageService(); - var tokens = service.GetDeclarations(container) - .SelectMany(r => r.GetSyntax(cancellationToken) - .DescendantTokens() - .Where(t => TokensMatch(state, t, symbol.Name))) - .ToImmutableArray(); + using var _ = ArrayBuilder.GetInstance(out var tokens); - return FindReferencesInTokensAsync(symbol, state, tokens, cancellationToken); + foreach (var declaration in service.GetDeclarations(container)) + { + var syntax = declaration.GetSyntax(cancellationToken); + if (syntax.SyntaxTree != state.SyntaxTree) + continue; + + foreach (var token in syntax.DescendantTokens()) + { + if (TokensMatch(state, token, symbol.Name)) + tokens.Add(token); + } + } + + return FindReferencesInTokensAsync(symbol, state, tokens.ToImmutable(), cancellationToken); } } } diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfoCacheService.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfoCacheService.cs index b1510a0680cb9..e8f4b149a2929 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfoCacheService.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfoCacheService.cs @@ -177,7 +177,7 @@ private async Task UpdateSourceSymbolTreeInfoAsync(Project project, Cancellation project, checksum, cancellationToken).ConfigureAwait(false); Contract.ThrowIfNull(info); - Contract.ThrowIfTrue(info.Checksum != checksum, "If we computed a SymbolTreeInfo, then its checksum much match our checksum."); + Contract.ThrowIfTrue(info.Checksum != checksum, "If we computed a SymbolTreeInfo, then its checksum must match our checksum."); // Mark that we're up to date with this project. Future calls with the same semantic-version or // checksum can bail out immediately. @@ -199,7 +199,7 @@ private async Task UpdateReferenceAsync( project.Solution, reference, checksum, cancellationToken).ConfigureAwait(false); Contract.ThrowIfNull(info); - Contract.ThrowIfTrue(info.Checksum != checksum, "If we computed a SymbolTreeInfo, then its checksum much match our checksum."); + Contract.ThrowIfTrue(info.Checksum != checksum, "If we computed a SymbolTreeInfo, then its checksum must match our checksum."); metadataInfo = new MetadataInfo(info, metadataInfo.ReferencingProjects ?? new HashSet()); _peReferenceToInfo[reference] = metadataInfo; diff --git a/src/Workspaces/Core/Portable/Formatting/Formatter.cs b/src/Workspaces/Core/Portable/Formatting/Formatter.cs index c2d79fbafba63..2f7452403eea3 100644 --- a/src/Workspaces/Core/Portable/Formatting/Formatter.cs +++ b/src/Workspaces/Core/Portable/Formatting/Formatter.cs @@ -319,16 +319,13 @@ internal static IList GetFormattedTextChanges(SyntaxNode node, IEnum internal static SyntaxFormattingOptions GetFormattingOptions(Workspace workspace, OptionSet? optionSet, string language) { var syntaxFormattingService = workspace.Services.GetRequiredLanguageService(language); - var optionService = workspace.Services.GetRequiredService(); - var configOptionSet = (optionSet ?? workspace.CurrentSolution.Options).AsAnalyzerConfigOptions(optionService, language); - return syntaxFormattingService.GetFormattingOptions(configOptionSet, fallbackOptions: null); + return syntaxFormattingService.GetFormattingOptions(optionSet ?? workspace.CurrentSolution.Options, fallbackOptions: null); } #pragma warning disable RS0030 // Do not used banned APIs (backwards compatibility) internal static async ValueTask<(SyntaxFormattingOptions? Syntax, LineFormattingOptions Line)> GetFormattingOptionsAsync(Document document, OptionSet? optionSet, CancellationToken cancellationToken) { - var optionService = document.Project.Solution.Services.GetRequiredService(); - var configOptionSet = (optionSet ?? await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false)).AsAnalyzerConfigOptions(optionService, document.Project.Language); + optionSet ??= await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); LineFormattingOptions lineFormattingOptions; SyntaxFormattingOptions? syntaxFormattingOptions; @@ -336,13 +333,13 @@ internal static SyntaxFormattingOptions GetFormattingOptions(Workspace workspace var syntaxFormattingService = document.GetLanguageService(); if (syntaxFormattingService != null) { - syntaxFormattingOptions = syntaxFormattingService.GetFormattingOptions(configOptionSet, fallbackOptions: null); + syntaxFormattingOptions = syntaxFormattingService.GetFormattingOptions(optionSet, fallbackOptions: null); lineFormattingOptions = syntaxFormattingOptions.LineFormatting; } else { syntaxFormattingOptions = null; - lineFormattingOptions = configOptionSet.GetLineFormattingOptions(fallbackOptions: null); + lineFormattingOptions = optionSet.GetLineFormattingOptions(document.Project.Language, fallbackOptions: null); } return (syntaxFormattingOptions, lineFormattingOptions); @@ -370,9 +367,8 @@ public static async Task OrganizeImportsAsync(Document document, Cance #pragma warning disable RS0030 // Do not used banned APIs (backwards compatibility) internal static async ValueTask GetOrganizeImportsOptionsAsync(Document document, CancellationToken cancellationToken) { - var optionService = document.Project.Solution.Services.GetRequiredService(); - var configOptionSet = (await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false)).AsAnalyzerConfigOptions(optionService, document.Project.Language); - return configOptionSet.GetOrganizeImportsOptions(fallbackOptions: null); + var optionSet = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); + return optionSet.GetOrganizeImportsOptions(document.Project.Language, fallbackOptions: null); } #pragma warning restore } diff --git a/src/Workspaces/Core/Portable/Formatting/FormattingOptions.cs b/src/Workspaces/Core/Portable/Formatting/FormattingOptions.cs index 6662f7a705c1b..1d0ea17aa4904 100644 --- a/src/Workspaces/Core/Portable/Formatting/FormattingOptions.cs +++ b/src/Workspaces/Core/Portable/Formatting/FormattingOptions.cs @@ -13,20 +13,18 @@ namespace Microsoft.CodeAnalysis.Formatting public static partial class FormattingOptions { /// - public static PerLanguageOption UseTabs { get; } = (PerLanguageOption)FormattingOptions2.UseTabs; + public static PerLanguageOption UseTabs { get; } = FormattingOptions2.UseTabs.ToPublicOption(); /// - public static PerLanguageOption TabSize { get; } = (PerLanguageOption)FormattingOptions2.TabSize; + public static PerLanguageOption TabSize { get; } = FormattingOptions2.TabSize.ToPublicOption(); /// - public static PerLanguageOption IndentationSize { get; } = (PerLanguageOption)FormattingOptions2.IndentationSize; + public static PerLanguageOption IndentationSize { get; } = FormattingOptions2.IndentationSize.ToPublicOption(); /// - public static PerLanguageOption NewLine { get; } = (PerLanguageOption)FormattingOptions2.NewLine; + public static PerLanguageOption NewLine { get; } = FormattingOptions2.NewLine.ToPublicOption(); /// - public static PerLanguageOption SmartIndent { get; } = new( - FormattingOptions2.SmartIndent.OptionDefinition, - FormattingOptions2.SmartIndent.StorageLocations.As()); + public static PerLanguageOption SmartIndent { get; } = (PerLanguageOption)FormattingOptions2.SmartIndent.PublicOption!; } } diff --git a/src/Workspaces/Core/Portable/Microsoft.CodeAnalysis.Workspaces.csproj b/src/Workspaces/Core/Portable/Microsoft.CodeAnalysis.Workspaces.csproj index fb91dd96d6348..fe7514f82b9ed 100644 --- a/src/Workspaces/Core/Portable/Microsoft.CodeAnalysis.Workspaces.csproj +++ b/src/Workspaces/Core/Portable/Microsoft.CodeAnalysis.Workspaces.csproj @@ -58,6 +58,7 @@ + @@ -147,6 +148,9 @@ + + + diff --git a/src/Workspaces/Core/Portable/Options/DocumentOptionSet.cs b/src/Workspaces/Core/Portable/Options/DocumentOptionSet.cs index cd4869c371d6c..6b730805f787e 100644 --- a/src/Workspaces/Core/Portable/Options/DocumentOptionSet.cs +++ b/src/Workspaces/Core/Portable/Options/DocumentOptionSet.cs @@ -9,7 +9,9 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Linq; +using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; using Microsoft.CodeAnalysis.ErrorReporting; using Roslyn.Utilities; @@ -24,9 +26,13 @@ public sealed class DocumentOptionSet : OptionSet { private readonly OptionSet _underlyingOptions; private readonly StructuredAnalyzerConfigOptions? _configOptions; - private ImmutableDictionary _values; private readonly string _language; + /// + /// Cached internal values read from or . + /// + private ImmutableDictionary _values; + internal DocumentOptionSet(StructuredAnalyzerConfigOptions? configOptions, OptionSet underlyingOptions, string language) : this(configOptions, underlyingOptions, language, ImmutableDictionary.Empty) { @@ -43,7 +49,7 @@ private DocumentOptionSet(StructuredAnalyzerConfigOptions? configOptions, Option internal string Language => _language; [PerformanceSensitive("https://github.com/dotnet/roslyn/issues/30819", AllowLocks = false)] - private protected override object? GetOptionCore(OptionKey optionKey) + internal override object? GetInternalOptionValue(OptionKey optionKey) { // If we already know the document specific value, we're done if (_values.TryGetValue(optionKey, out var value)) @@ -58,10 +64,10 @@ private DocumentOptionSet(StructuredAnalyzerConfigOptions? configOptions, Option } // We don't have a document specific value, so forward - return _underlyingOptions.GetOption(optionKey); + return _underlyingOptions.GetInternalOptionValue(optionKey); } - private bool TryGetAnalyzerConfigOption(OptionKey option, out object? value) + private bool TryGetAnalyzerConfigOption(OptionKey optionKey, out object? value) { if (_configOptions == null) { @@ -69,52 +75,35 @@ private bool TryGetAnalyzerConfigOption(OptionKey option, out object? value) return false; } - var editorConfigPersistence = (IEditorConfigStorageLocation?)option.Option.StorageLocations.SingleOrDefault(static location => location is IEditorConfigStorageLocation); - if (editorConfigPersistence == null) + if (optionKey.Option is not IOption2 internallyDefinedOption) { value = null; return false; } - try - { - return editorConfigPersistence.TryGetOption(_configOptions, option.Option.Type, out value); - } - catch (Exception e) when (FatalError.ReportAndCatch(e)) + // Naming style option is not public. We should not call this API internally. + Contract.ThrowIfTrue(internallyDefinedOption.Type == typeof(NamingStylePreferences)); + + if (!_configOptions.TryGetValue(internallyDefinedOption.Definition.ConfigName, out var stringValue)) { value = null; return false; } + + // The option is in _configOptions so it must have editorconfig storage location: + return internallyDefinedOption.Definition.Serializer.TryParse(stringValue, out value); } public T GetOption(PerLanguageOption option) => GetOption(option, _language); - internal T GetOption(PerLanguageOption2 option) - => GetOption(option, _language); - - public override OptionSet WithChangedOption(OptionKey optionAndLanguage, object? value) - => new DocumentOptionSet(_configOptions, _underlyingOptions, _language, _values.SetItem(optionAndLanguage, value)); + internal override OptionSet WithChangedOptionInternal(OptionKey optionKey, object? internalValue) + => new DocumentOptionSet(_configOptions, _underlyingOptions, _language, _values.SetItem(optionKey, internalValue)); /// /// Creates a new that contains the changed value. /// public DocumentOptionSet WithChangedOption(PerLanguageOption option, T value) => (DocumentOptionSet)WithChangedOption(option, _language, value); - - /// - /// Creates a new that contains the changed value. - /// - internal DocumentOptionSet WithChangedOption(PerLanguageOption2 option, T value) - => (DocumentOptionSet)WithChangedOption(option, _language, value); - - private protected override AnalyzerConfigOptions CreateAnalyzerConfigOptions(IEditorConfigOptionMappingService optionService, string? language) - { - Debug.Assert((language ?? _language) == _language, $"Use of a {nameof(DocumentOptionSet)} is not expected to differ from the language it was constructed with."); - return base.CreateAnalyzerConfigOptions(optionService, language ?? _language); - } - - internal override IEnumerable GetChangedOptions(OptionSet optionSet) - => GetChangedOptions(optionSet); } } diff --git a/src/Workspaces/Core/Portable/Options/EditorConfig/EditorConfigFileGenerator.cs b/src/Workspaces/Core/Portable/Options/EditorConfig/EditorConfigFileGenerator.cs index 7a69ccbf0e57a..e20d3885e63e2 100644 --- a/src/Workspaces/Core/Portable/Options/EditorConfig/EditorConfigFileGenerator.cs +++ b/src/Workspaces/Core/Portable/Options/EditorConfig/EditorConfigFileGenerator.cs @@ -4,19 +4,20 @@ using System.Collections.Generic; using System.Collections.Immutable; -using System.Diagnostics; using System.Linq; using System.Text; using Microsoft.CodeAnalysis.CodeStyle; -using Microsoft.CodeAnalysis.Simplification; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Options { internal static partial class EditorConfigFileGenerator { public static string Generate( - ImmutableArray<(string feature, ImmutableArray options)> groupedOptions, - OptionSet optionSet, + ImmutableArray<(string feature, ImmutableArray options)> groupedOptions, + IOptionsReader configOptions, string language) { var editorconfig = new StringBuilder(); @@ -40,33 +41,34 @@ public static string Generate( foreach ((var feature, var options) in groupedOptions) { - AppendOptionsToEditorConfig(optionSet, feature, options, language, editorconfig); + AppendOptionsToEditorConfig(configOptions, feature, options, language, editorconfig); } - var namingStylePreferences = optionSet.GetOption(NamingStyleOptions.NamingPreferences, language); - AppendNamingStylePreferencesToEditorConfig(namingStylePreferences, language, editorconfig); + if (configOptions.TryGetOption(new OptionKey2(NamingStyleOptions.NamingPreferences, language), out NamingStylePreferences namingStylePreferences)) + { + AppendNamingStylePreferencesToEditorConfig(namingStylePreferences, language, editorconfig); + } return editorconfig.ToString(); } - private static void AppendOptionsToEditorConfig(OptionSet optionSet, string feature, ImmutableArray options, string language, StringBuilder editorconfig) + private static void AppendOptionsToEditorConfig(IOptionsReader configOptions, string feature, ImmutableArray options, string language, StringBuilder editorconfig) { editorconfig.AppendLine($"#### {feature} ####"); editorconfig.AppendLine(); - foreach (var optionGrouping in options - .Where(o => o.StorageLocations.Any(static l => l is IEditorConfigStorageLocation2)) - .GroupBy(o => (o as IOptionWithGroup)?.Group ?? OptionGroup.Default) - .OrderBy(g => g.Key.Priority)) + foreach (var optionGrouping in options.GroupBy(o => o.Definition.Group).OrderBy(g => g.Key.Priority)) { editorconfig.AppendLine($"# {optionGrouping.Key.Description}"); - var optionsAndEditorConfigLocations = optionGrouping.Select(o => (o, o.StorageLocations.OfType().First())); var uniqueEntries = new SortedSet(); - foreach ((var option, var editorConfigLocation) in optionsAndEditorConfigLocations) + foreach (var option in optionGrouping) { - var editorConfigString = GetEditorConfigString(option, editorConfigLocation); - uniqueEntries.Add(editorConfigString); + var optionKey = new OptionKey2(option, option.IsPerLanguage ? language : null); + if (configOptions.TryGetOption(optionKey, out var value)) + { + uniqueEntries.Add($"{option.Definition.ConfigName} = {option.Definition.Serializer.Serialize(value)}"); + } } foreach (var entry in uniqueEntries) @@ -76,14 +78,6 @@ private static void AppendOptionsToEditorConfig(OptionSet optionSet, string feat editorconfig.AppendLine(); } - - string GetEditorConfigString(IOption option, IEditorConfigStorageLocation2 editorConfigLocation) - { - var optionKey = new OptionKey(option, option.IsPerLanguage ? language : null); - var editorConfigString = editorConfigLocation.GetEditorConfigString(optionKey, optionSet); - Debug.Assert(!string.IsNullOrEmpty(editorConfigString)); - return editorConfigString; - } } } } diff --git a/src/Workspaces/Core/Portable/Options/EditorConfigOptionMappingService.cs b/src/Workspaces/Core/Portable/Options/EditorConfigOptionMappingService.cs deleted file mode 100644 index 33731b68375eb..0000000000000 --- a/src/Workspaces/Core/Portable/Options/EditorConfigOptionMappingService.cs +++ /dev/null @@ -1,166 +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.Composition; -using System.Diagnostics.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options.Providers; -using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.Options -{ - [ExportWorkspaceService(typeof(IEditorConfigOptionMappingService)), Shared] - internal sealed class EditorConfigOptionMappingService : IEditorConfigOptionMappingService - { - private static readonly ImmutableDictionary s_emptyEditorConfigKeysToOptions - = ImmutableDictionary.Create(AnalyzerConfigOptions.KeyComparer); - - private ImmutableDictionary _neutralEditorConfigKeysToOptions = s_emptyEditorConfigKeysToOptions; - private ImmutableDictionary _csharpEditorConfigKeysToOptions = s_emptyEditorConfigKeysToOptions; - private ImmutableDictionary _visualBasicEditorConfigKeysToOptions = s_emptyEditorConfigKeysToOptions; - - private readonly ImmutableDictionary>> _serializableOptionsByLanguage; - - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public EditorConfigOptionMappingService( - [ImportMany] IEnumerable> optionProviders) - { - _serializableOptionsByLanguage = CreateLazySerializableOptionsByLanguage(optionProviders); - } - - private static ImmutableDictionary>> CreateLazySerializableOptionsByLanguage(IEnumerable> optionProviders) - { - var builder = ImmutableDictionary.CreateBuilder>>(); - - foreach (var (language, lazyProvidersAndMetadata) in optionProviders.ToPerLanguageMap()) - { - builder.Add(language, new Lazy>(() => ComputeSerializableOptionsFromProviders(lazyProvidersAndMetadata))); - } - - return builder.ToImmutable(); - - // Local functions - static ImmutableHashSet ComputeSerializableOptionsFromProviders(ImmutableArray> lazyProvidersAndMetadata) - { - var builder = ImmutableHashSet.CreateBuilder(); - - foreach (var lazyProviderAndMetadata in lazyProvidersAndMetadata) - { - var provider = lazyProviderAndMetadata.Value; - if (!IsSolutionOptionProvider(provider)) - { - continue; - } - - builder.AddRange(provider.Options); - } - - return builder.ToImmutable(); - } - } - - // We only consider the options defined in the the DefaultAssemblies (Workspaces and Features) as serializable. - // This is due to the fact that other layers above are VS specific and do not execute in OOP. - internal static bool IsSolutionOptionProvider(IOptionProvider provider) - => MefHostServices.IsDefaultAssembly(provider.GetType().Assembly); - - public bool TryMapEditorConfigKeyToOption(string key, string? language, [NotNullWhen(true)] out IEditorConfigStorageLocation2? storageLocation, out OptionKey optionKey) - { - var temporaryOptions = s_emptyEditorConfigKeysToOptions; - ref var editorConfigToOptionsStorage = ref temporaryOptions; - switch (language) - { - case LanguageNames.CSharp: - editorConfigToOptionsStorage = ref _csharpEditorConfigKeysToOptions!; - break; - - case LanguageNames.VisualBasic: - editorConfigToOptionsStorage = ref _visualBasicEditorConfigKeysToOptions!; - break; - - case null: - case "": - editorConfigToOptionsStorage = ref _neutralEditorConfigKeysToOptions!; - break; - } - - var (option, storage) = ImmutableInterlocked.GetOrAdd( - ref editorConfigToOptionsStorage, - key, - (key, arg) => MapToOptionIgnorePerLanguage(arg.self, key, arg.language), - (self: this, language)); - - if (option is object) - { - RoslynDebug.AssertNotNull(storage); - storageLocation = storage; - optionKey = option.IsPerLanguage ? new OptionKey(option, language) : new OptionKey(option); - return true; - } - - storageLocation = null; - optionKey = default; - return false; - - // Local function - static (IOption? option, IEditorConfigStorageLocation2? storageLocation) MapToOptionIgnorePerLanguage(EditorConfigOptionMappingService service, string key, string? language) - { - // Use GetRegisteredSerializableOptions instead of GetRegisteredOptions to avoid loading assemblies for - // inactive languages. - foreach (var option in service.GetRegisteredSerializableOptions(ImmutableHashSet.Create(language ?? ""))) - { - foreach (var storage in option.StorageLocations) - { - if (storage is not IEditorConfigStorageLocation2 editorConfigStorage) - continue; - - if (!AnalyzerConfigOptions.KeyComparer.Equals(key, editorConfigStorage.KeyName)) - continue; - - return (option, editorConfigStorage); - } - } - - return (null, null); - } - } - - public ImmutableHashSet GetRegisteredSerializableOptions(ImmutableHashSet languages) - { - if (languages.IsEmpty) - { - return ImmutableHashSet.Empty; - } - - var builder = ImmutableHashSet.CreateBuilder(); - - // "string.Empty" for options from language agnostic option providers. - builder.AddRange(GetSerializableOptionsForLanguage(string.Empty)); - - foreach (var language in languages) - { - builder.AddRange(GetSerializableOptionsForLanguage(language)); - } - - return builder.ToImmutable(); - - // Local functions. - ImmutableHashSet GetSerializableOptionsForLanguage(string language) - { - if (_serializableOptionsByLanguage.TryGetValue(language, out var lazyOptions)) - { - return lazyOptions.Value; - } - - return ImmutableHashSet.Empty; - } - } - } -} diff --git a/src/Workspaces/Core/Portable/Options/EmptyOptionSet.cs b/src/Workspaces/Core/Portable/Options/EmptyOptionSet.cs new file mode 100644 index 0000000000000..cb3f5cea97212 --- /dev/null +++ b/src/Workspaces/Core/Portable/Options/EmptyOptionSet.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; + +namespace Microsoft.CodeAnalysis.Options; + +public abstract partial class OptionSet +{ + private sealed class EmptyOptionSet : OptionSet + { + internal override object? GetInternalOptionValue(OptionKey optionKey) + => optionKey.Option.DefaultValue; + + internal override OptionSet WithChangedOptionInternal(OptionKey optionKey, object? internalValue) + => throw new NotSupportedException(); + } +} diff --git a/src/Workspaces/Core/Portable/Options/GlobalOptionService.cs b/src/Workspaces/Core/Portable/Options/GlobalOptionService.cs index f76b3860aaa02..b00367b048367 100644 --- a/src/Workspaces/Core/Portable/Options/GlobalOptionService.cs +++ b/src/Workspaces/Core/Portable/Options/GlobalOptionService.cs @@ -8,15 +8,9 @@ using System.Composition; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options.Providers; -using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Shared.Collections; -using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; using Roslyn.Utilities; @@ -28,35 +22,27 @@ internal sealed class GlobalOptionService : IGlobalOptionService private readonly IWorkspaceThreadingService? _workspaceThreadingService; private readonly ImmutableArray> _optionPersisterProviders; - // access is interlocked - private ImmutableArray _registeredWorkspaces; - private readonly object _gate = new(); - private readonly Func _getOption; #region Guarded by _gate private ImmutableArray _lazyOptionPersisters; - - private ImmutableDictionary _currentValues; - private ImmutableHashSet _changedOptionKeys; + private ImmutableDictionary _currentValues; #endregion + public event EventHandler? OptionChanged; + [ImportingConstructor] [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] public GlobalOptionService( [Import(AllowDefault = true)] IWorkspaceThreadingService? workspaceThreadingService, [ImportMany] IEnumerable> optionPersisters) { - _getOption = GetOption; - _workspaceThreadingService = workspaceThreadingService; _optionPersisterProviders = optionPersisters.ToImmutableArray(); - _registeredWorkspaces = ImmutableArray.Empty; - _currentValues = ImmutableDictionary.Create(); - _changedOptionKeys = ImmutableHashSet.Empty; + _currentValues = ImmutableDictionary.Create(); } private ImmutableArray GetOptionPersisters() @@ -100,7 +86,7 @@ static async Task> GetOptionPersistersAsync( } } - private static object? LoadOptionFromPersisterOrGetDefault(OptionKey optionKey, ImmutableArray persisters) + private static object? LoadOptionFromPersisterOrGetDefault(OptionKey2 optionKey, ImmutableArray persisters) { foreach (var persister in persisters) { @@ -115,24 +101,30 @@ static async Task> GetOptionPersistersAsync( return optionKey.Option.DefaultValue; } + bool IOptionsReader.TryGetOption(OptionKey2 optionKey, out T value) + { + value = GetOption(optionKey); + return true; + } + public T GetOption(Option2 option) - => OptionsHelpers.GetOption(option, _getOption); + => GetOption(new OptionKey2(option)); - public T GetOption(PerLanguageOption2 option, string? language) - => OptionsHelpers.GetOption(option, language, _getOption); + public T GetOption(PerLanguageOption2 option, string language) + => GetOption(new OptionKey2(option, language)); - public object? GetOption(OptionKey optionKey) + public T GetOption(OptionKey2 optionKey) { // Ensure the option persisters are available before taking the global lock var persisters = GetOptionPersisters(); lock (_gate) { - return GetOption_NoLock(optionKey, persisters); + return (T)GetOption_NoLock(optionKey, persisters)!; } } - public ImmutableArray GetOptions(ImmutableArray optionKeys) + public ImmutableArray GetOptions(ImmutableArray optionKeys) { // Ensure the option persisters are available before taking the global lock var persisters = GetOptionPersisters(); @@ -149,8 +141,11 @@ public T GetOption(PerLanguageOption2 option, string? language) return values.ToImmutableAndClear(); } - private object? GetOption_NoLock(OptionKey optionKey, ImmutableArray persisters) + private object? GetOption_NoLock(OptionKey2 optionKey, ImmutableArray persisters) { + // The option must be internally defined and it can't be a legacy option whose value is mapped to another option: + Debug.Assert(optionKey.Option is IOption2 { Definition.StorageMapping: null }); + if (_currentValues.TryGetValue(optionKey, out var value)) { return value; @@ -160,93 +155,56 @@ public T GetOption(PerLanguageOption2 option, string? language) _currentValues = _currentValues.Add(optionKey, value); - // Track options with non-default values from serializers as changed options. - if (!object.Equals(value, optionKey.Option.DefaultValue)) - { - _changedOptionKeys = _changedOptionKeys.Add(optionKey); - } - return value; } - private void SetOptionCore(OptionKey optionKey, object? newValue) - { - _currentValues = _currentValues.SetItem(optionKey, newValue); - _changedOptionKeys = _changedOptionKeys.Add(optionKey); - } + public void SetGlobalOption(Option2 option, T value) + => SetGlobalOption(new OptionKey2(option), value); - public void SetGlobalOption(OptionKey optionKey, object? value) - => SetGlobalOptions(ImmutableArray.Create(optionKey), ImmutableArray.Create(value)); + public void SetGlobalOption(PerLanguageOption2 option, string language, T value) + => SetGlobalOption(new OptionKey2(option, language), value); - public void SetGlobalOptions(ImmutableArray optionKeys, ImmutableArray values) - { - Contract.ThrowIfFalse(optionKeys.Length == values.Length); + public void SetGlobalOption(OptionKey2 optionKey, object? value) + => SetGlobalOptions(OneOrMany.Create(KeyValuePairUtil.Create(optionKey, value))); + public bool SetGlobalOptions(ImmutableArray> options) + => SetGlobalOptions(OneOrMany.Create(options)); + + private bool SetGlobalOptions(OneOrMany> options) + { var changedOptions = new List(); var persisters = GetOptionPersisters(); lock (_gate) { - for (var i = 0; i < optionKeys.Length; i++) + foreach (var (optionKey, value) in options) { - var optionKey = optionKeys[i]; - var value = values[i]; - var existingValue = GetOption_NoLock(optionKey, persisters); if (Equals(value, existingValue)) { continue; } - // not updating _changedOptionKeys since that's only relevant for serializable options, not global ones _currentValues = _currentValues.SetItem(optionKey, value); changedOptions.Add(new OptionChangedEventArgs(optionKey, value)); } } - for (var i = 0; i < optionKeys.Length; i++) + if (changedOptions.Count == 0) { - PersistOption(persisters, optionKeys[i], values[i]); + return false; } - RaiseOptionChangedEvent(changedOptions); - } - - public void SetOptions(OptionSet optionSet, IEnumerable optionKeys) - { - var changedOptions = new List(); - - lock (_gate) - { - foreach (var optionKey in optionKeys) - { - var newValue = optionSet.GetOption(optionKey); - var currentValue = GetOption(optionKey); - - if (Equals(currentValue, newValue)) - { - // Identical, so nothing is changing - continue; - } - - // The value is actually changing, so update - changedOptions.Add(new OptionChangedEventArgs(optionKey, newValue)); - - SetOptionCore(optionKey, newValue); - } - } - - var persisters = GetOptionPersisters(); foreach (var changedOption in changedOptions) { PersistOption(persisters, changedOption.OptionKey, changedOption.Value); } - // Outside of the lock, raise the events on our task queue. - UpdateRegisteredWorkspacesAndRaiseEvents(changedOptions); + RaiseOptionChangedEvent(changedOptions); + return true; } - private static void PersistOption(ImmutableArray persisters, OptionKey optionKey, object? value) + private static void PersistOption(ImmutableArray persisters, OptionKey2 optionKey, object? value) { foreach (var persister in persisters) { @@ -257,44 +215,31 @@ private static void PersistOption(ImmutableArray persisters, O } } - public void RefreshOption(OptionKey optionKey, object? newValue) + public bool RefreshOption(OptionKey2 optionKey, object? newValue) { lock (_gate) { if (_currentValues.TryGetValue(optionKey, out var oldValue)) { - if (object.Equals(oldValue, newValue)) + if (Equals(oldValue, newValue)) { // Value is still the same, no reason to raise events - return; + return false; } } - SetOptionCore(optionKey, newValue); - } - - UpdateRegisteredWorkspacesAndRaiseEvents(new List { new OptionChangedEventArgs(optionKey, newValue) }); - } - - private void UpdateRegisteredWorkspacesAndRaiseEvents(List changedOptions) - { - if (changedOptions.Count == 0) - { - return; - } - - // Ensure that the Workspace's CurrentSolution snapshot is updated with new options for all registered workspaces - // prior to raising option changed event handlers. - foreach (var workspace in _registeredWorkspaces) - { - workspace.UpdateCurrentSolutionOnOptionsChanged(); + _currentValues = _currentValues.SetItem(optionKey, newValue); } + var changedOptions = new List { new OptionChangedEventArgs(optionKey, newValue) }; RaiseOptionChangedEvent(changedOptions); + return true; } private void RaiseOptionChangedEvent(List changedOptions) { + Debug.Assert(changedOptions.Count > 0); + // Raise option changed events. var optionChanged = OptionChanged; if (optionChanged != null) @@ -306,12 +251,13 @@ private void RaiseOptionChangedEvent(List changedOptions } } - public void RegisterWorkspace(Workspace workspace) - => ImmutableInterlocked.Update(ref _registeredWorkspaces, (workspaces, workspace) => workspaces.Add(workspace), workspace); - - public void UnregisterWorkspace(Workspace workspace) - => ImmutableInterlocked.Update(ref _registeredWorkspaces, (workspaces, workspace) => workspaces.Remove(workspace), workspace); - - public event EventHandler? OptionChanged; + // for testing + public void ClearCachedValues() + { + lock (_gate) + { + _currentValues = ImmutableDictionary.Create(); + } + } } } diff --git a/src/Workspaces/Core/Portable/Options/IEditorConfigOptionMappingService.cs b/src/Workspaces/Core/Portable/Options/IEditorConfigOptionMappingService.cs deleted file mode 100644 index 2b8eeba2a66a8..0000000000000 --- a/src/Workspaces/Core/Portable/Options/IEditorConfigOptionMappingService.cs +++ /dev/null @@ -1,24 +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.Diagnostics.CodeAnalysis; -using Microsoft.CodeAnalysis.Host; - -namespace Microsoft.CodeAnalysis.Options -{ - internal interface IEditorConfigOptionMappingService : IWorkspaceService - { - /// - /// Map an .editorconfig key to a corresponding and - /// that can be used to read and write the value stored in an . - /// - /// The .editorconfig key. - /// The language to use for the , if the matching option has - /// set. - /// The for the key. - /// The for the key and language. - /// if a matching option was found; otherwise, . - bool TryMapEditorConfigKeyToOption(string key, string? language, [NotNullWhen(true)] out IEditorConfigStorageLocation2? storageLocation, out OptionKey optionKey); - } -} diff --git a/src/Workspaces/Core/Portable/Options/IGlobalOptionService.cs b/src/Workspaces/Core/Portable/Options/IGlobalOptionService.cs index 1b38f4379bcf2..ab71f0ec22878 100644 --- a/src/Workspaces/Core/Portable/Options/IGlobalOptionService.cs +++ b/src/Workspaces/Core/Portable/Options/IGlobalOptionService.cs @@ -5,9 +5,6 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Diagnostics.CodeAnalysis; -using Microsoft.CodeAnalysis.CodeCleanup; -using Microsoft.CodeAnalysis.Host; namespace Microsoft.CodeAnalysis.Options { @@ -15,7 +12,7 @@ namespace Microsoft.CodeAnalysis.Options /// Provides services for reading and writing global client (in-proc) options /// shared across all workspaces. /// - internal interface IGlobalOptionService + internal interface IGlobalOptionService : IOptionsReader { /// /// Gets the current value of the specific option. @@ -25,56 +22,49 @@ internal interface IGlobalOptionService /// /// Gets the current value of the specific option. /// - T GetOption(PerLanguageOption2 option, string? languageName); + T GetOption(PerLanguageOption2 option, string language); /// /// Gets the current value of the specific option. /// - object? GetOption(OptionKey optionKey); + T GetOption(OptionKey2 optionKey); /// /// Gets the current values of specified options. /// All options are read atomically. /// - ImmutableArray GetOptions(ImmutableArray optionKeys); + ImmutableArray GetOptions(ImmutableArray optionKeys); - /// - /// Applies a set of options. - /// If any option changed its value invokes registered option persisters, updates current solutions of all registered workspaces and triggers . - /// - void SetOptions(OptionSet optionSet, IEnumerable optionKeys); + void SetGlobalOption(Option2 option, T value); + + void SetGlobalOption(PerLanguageOption2 option, string language, T value); /// /// Sets and persists the value of a global option. /// Sets the value of a global option. /// Invokes registered option persisters. /// Triggers . - /// Does not update any workspace (since this option is not a solution option). /// - void SetGlobalOption(OptionKey optionKey, object? value); + void SetGlobalOption(OptionKey2 optionKey, object? value); /// /// Atomically sets the values of specified global options. The option values are persisted. /// Triggers . - /// Does not update any workspace (since this option is not a solution option). /// - void SetGlobalOptions(ImmutableArray optionKeys, ImmutableArray values); + /// + /// Returns true if any option changed its value stored in the global options. + /// + bool SetGlobalOptions(ImmutableArray> options); event EventHandler? OptionChanged; /// - /// Refreshes the stored value of a serialized option. This should only be called from serializers. - /// - void RefreshOption(OptionKey optionKey, object? newValue); - - /// - /// Registers a workspace with the option service. - /// - void RegisterWorkspace(Workspace workspace); - - /// - /// Unregisters a workspace from the option service. + /// Refreshes the stored value of an option. This should only be called from persisters. + /// Does not persist the new option value. /// - void UnregisterWorkspace(Workspace workspace); + /// + /// Returns true if the option changed its value stored in the global options. + /// + bool RefreshOption(OptionKey2 optionKey, object? newValue); } } diff --git a/src/Workspaces/Core/Portable/Options/ILegacyWorkspaceOptionService.cs b/src/Workspaces/Core/Portable/Options/ILegacyWorkspaceOptionService.cs index 3714664667bd4..579349a4cb9d9 100644 --- a/src/Workspaces/Core/Portable/Options/ILegacyWorkspaceOptionService.cs +++ b/src/Workspaces/Core/Portable/Options/ILegacyWorkspaceOptionService.cs @@ -2,12 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Diagnostics.CodeAnalysis; -using System.Threading; -using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; namespace Microsoft.CodeAnalysis.Options; @@ -17,12 +13,21 @@ namespace Microsoft.CodeAnalysis.Options; /// and . /// internal interface ILegacyWorkspaceOptionService : IWorkspaceService +{ + ILegacyGlobalOptionService LegacyGlobalOptions { get; } +} + +internal interface ILegacyGlobalOptionService { IGlobalOptionService GlobalOptions { get; } void RegisterWorkspace(Workspace workspace); void UnregisterWorkspace(Workspace workspace); + void UpdateRegisteredWorkspaces(); + + object? GetExternallyDefinedOption(OptionKey key); - object? GetOption(OptionKey key); - void SetOptions(OptionSet optionSet, IEnumerable optionKeys); + void SetOptions( + ImmutableArray> internallyDefinedOptions, + ImmutableArray> externallyDefinedOptions); } diff --git a/src/Workspaces/Core/Portable/Options/IOptionPersister.cs b/src/Workspaces/Core/Portable/Options/IOptionPersister.cs index 9f227e941f3af..7e1319f9dd3dc 100644 --- a/src/Workspaces/Core/Portable/Options/IOptionPersister.cs +++ b/src/Workspaces/Core/Portable/Options/IOptionPersister.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.Options /// internal interface IOptionPersister { - bool TryFetch(OptionKey optionKey, out object? value); - bool TryPersist(OptionKey optionKey, object? value); + bool TryFetch(OptionKey2 optionKey, out object? value); + bool TryPersist(OptionKey2 optionKey, object? value); } } diff --git a/src/Workspaces/Core/Portable/Options/LegacyWorkspaceOptionService.cs b/src/Workspaces/Core/Portable/Options/LegacyWorkspaceOptionService.cs new file mode 100644 index 0000000000000..23aa69abff501 --- /dev/null +++ b/src/Workspaces/Core/Portable/Options/LegacyWorkspaceOptionService.cs @@ -0,0 +1,117 @@ +// 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.Composition; +using System.Diagnostics; +using System.Linq; +using Microsoft.CodeAnalysis.Host.Mef; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Options; + +[Export(typeof(ILegacyGlobalOptionService)), Shared] +internal sealed class LegacyGlobalOptionService : ILegacyGlobalOptionService +{ + [ExportWorkspaceService(typeof(ILegacyWorkspaceOptionService)), Shared] + internal sealed class WorkspaceService : ILegacyWorkspaceOptionService + { + public ILegacyGlobalOptionService LegacyGlobalOptions { get; } + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public WorkspaceService(ILegacyGlobalOptionService legacyGlobalOptions) + => LegacyGlobalOptions = legacyGlobalOptions; + } + + public IGlobalOptionService GlobalOptions { get; } + + // access is interlocked + private ImmutableArray _registeredWorkspaces; + + /// + /// Stores options that are not defined by Roslyn and do not implement . + /// + private ImmutableDictionary _currentExternallyDefinedOptionValues; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public LegacyGlobalOptionService(IGlobalOptionService globalOptionService) + { + GlobalOptions = globalOptionService; + _registeredWorkspaces = ImmutableArray.Empty; + _currentExternallyDefinedOptionValues = ImmutableDictionary.Create(); + } + + public object? GetExternallyDefinedOption(OptionKey key) + { + Debug.Assert(key.Option is not IOption2); + return _currentExternallyDefinedOptionValues.TryGetValue(key, out var value) ? value : key.Option.DefaultValue; + } + + /// + /// Sets values of options that may be stored in (public options). + /// Clears of registered workspaces so that next time + /// are queried for the options new values are fetched from + /// . + /// + public void SetOptions( + ImmutableArray> internallyDefinedOptions, + ImmutableArray> externallyDefinedOptions) + { + // all values in internally defined options have internal representation: + Debug.Assert(internallyDefinedOptions.All(entry => OptionSet.IsInternalOptionValue(entry.Value))); + + var anyExternallyDefinedOptionChanged = false; + foreach (var (optionKey, value) in externallyDefinedOptions) + { + if (Equals(value, GetExternallyDefinedOption(optionKey))) + { + continue; + } + + anyExternallyDefinedOptionChanged = true; + + ImmutableInterlocked.Update( + ref _currentExternallyDefinedOptionValues, + static (options, arg) => options.SetItem(arg.optionKey, arg.value), + (optionKey, value)); + } + + // Update workspaces even when value of public internally defined options have not actually changed. + // This is necessary since these options may have been changed previously directly via IGlobalOptionService, + // without updating the workspaces and thus the values stored in IGlobalOptionService may not match the values + // stored on current solution snapshots. + // + // Updating workspaces more often than strictly needed is not a functional issue - + // it's just adding a bit of extra overhead since the options need to be re-read from global options. + if (!internallyDefinedOptions.IsEmpty || anyExternallyDefinedOptionChanged) + { + UpdateRegisteredWorkspaces(); + } + + // Update global options after updating registered workspaces, + // so that the handler of the changed event has access to the updated values through the current solution. + GlobalOptions.SetGlobalOptions(internallyDefinedOptions); + } + + public void UpdateRegisteredWorkspaces() + { + // Ensure that the Workspace's CurrentSolution snapshot is updated with new options for all registered workspaces + // prior to raising option changed event handlers. + foreach (var workspace in _registeredWorkspaces) + { + workspace.UpdateCurrentSolutionOnOptionsChanged(); + } + } + + public void RegisterWorkspace(Workspace workspace) + => ImmutableInterlocked.Update(ref _registeredWorkspaces, (workspaces, workspace) => workspaces.Add(workspace), workspace); + + public void UnregisterWorkspace(Workspace workspace) + => ImmutableInterlocked.Update(ref _registeredWorkspaces, (workspaces, workspace) => workspaces.Remove(workspace), workspace); + +} diff --git a/src/Workspaces/Core/Portable/Options/Option`1.cs b/src/Workspaces/Core/Portable/Options/Option.cs similarity index 58% rename from src/Workspaces/Core/Portable/Options/Option`1.cs rename to src/Workspaces/Core/Portable/Options/Option.cs index 52a75beb9913d..9aa7a491a68a4 100644 --- a/src/Workspaces/Core/Portable/Options/Option`1.cs +++ b/src/Workspaces/Core/Portable/Options/Option.cs @@ -7,31 +7,25 @@ using System; using System.Collections.Immutable; using System.Diagnostics; -using Roslyn.Utilities; +using System.Linq; namespace Microsoft.CodeAnalysis.Options { /// - public class Option : ISingleValuedOption + public class Option : IPublicOption { private readonly OptionDefinition _optionDefinition; - /// - public string Feature => _optionDefinition.Feature; + public string Feature { get; } - /// internal OptionGroup Group => _optionDefinition.Group; - /// - public string Name => _optionDefinition.Name; + public string Name { get; } - /// public T DefaultValue => (T)_optionDefinition.DefaultValue!; - /// public Type Type => _optionDefinition.Type; - /// public ImmutableArray StorageLocations { get; } [Obsolete("Use a constructor that specifies an explicit default value.")] @@ -43,53 +37,59 @@ public Option(string feature, string name) public Option(string feature, string name, T defaultValue) : this(feature ?? throw new ArgumentNullException(nameof(feature)), - OptionGroup.Default, name ?? throw new ArgumentNullException(nameof(name)), + OptionGroup.Default, defaultValue, - storageLocations: ImmutableArray.Empty) + storageLocations: ImmutableArray.Empty, + storageMapping: null, + isEditorConfigOption: false) { } public Option(string feature, string name, T defaultValue, params OptionStorageLocation[] storageLocations) : this(feature ?? throw new ArgumentNullException(nameof(feature)), - OptionGroup.Default, name ?? throw new ArgumentNullException(nameof(name)), + OptionGroup.Default, defaultValue, - (storageLocations ?? throw new ArgumentNullException(nameof(storageLocations))).ToImmutableArray()) + PublicContract.RequireNonNullItems(storageLocations, nameof(storageLocations)).ToImmutableArray(), + storageMapping: null, + isEditorConfigOption: false) { + // should not be used internally to create options + Debug.Assert(storageLocations.All(l => l is not IEditorConfigValueSerializer)); } - internal Option(string? feature, OptionGroup group, string? name, T defaultValue, ImmutableArray storageLocations) - : this(new OptionDefinition(feature, group, name, storageLocations.GetOptionConfigName(feature, name), defaultValue, typeof(T)), storageLocations) + internal Option( + string feature, + string name, + OptionGroup group, + T defaultValue, + ImmutableArray storageLocations, + OptionStorageMapping? storageMapping, + bool isEditorConfigOption) + : this(new OptionDefinition(defaultValue, EditorConfigValueSerializer.Unsupported, group, feature + "_" + name, storageMapping, isEditorConfigOption), feature, name, storageLocations) { } - internal Option(OptionDefinition optionDefinition, ImmutableArray storageLocations) + internal Option(OptionDefinition optionDefinition, string feature, string name, ImmutableArray storageLocations) { + Feature = feature; + Name = name; _optionDefinition = optionDefinition; - this.StorageLocations = storageLocations; + StorageLocations = storageLocations; } - OptionGroup IOptionWithGroup.Group => this.Group; - object? IOption.DefaultValue => this.DefaultValue; bool IOption.IsPerLanguage => false; - OptionDefinition IOption2.OptionDefinition => _optionDefinition; + IPublicOption? IOption2.PublicOption => null; - string? ISingleValuedOption.LanguageName - { - get - { - Debug.Fail("It's not expected that we access LanguageName property for Option. The options we use should be Option2."); - return null; - } - } + OptionDefinition IOption2.Definition => _optionDefinition; bool IEquatable.Equals(IOption2? other) => Equals(other); - public override string ToString() => _optionDefinition.PublicOptionDefinitionToString(); + public override string ToString() => this.PublicOptionDefinitionToString(); public override int GetHashCode() => _optionDefinition.GetHashCode(); @@ -102,7 +102,7 @@ private bool Equals(IOption2? other) return true; } - return other is not null && _optionDefinition.PublicOptionDefinitionEquals(other.OptionDefinition); + return other is not null && this.PublicOptionDefinitionEquals(other); } public static implicit operator OptionKey(Option option) diff --git a/src/Workspaces/Core/Portable/Options/Option2`1_operators.cs b/src/Workspaces/Core/Portable/Options/Option2`1_operators.cs deleted file mode 100644 index 1f7a64633f5d2..0000000000000 --- a/src/Workspaces/Core/Portable/Options/Option2`1_operators.cs +++ /dev/null @@ -1,24 +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. - -#pragma warning disable RS0030 // Do not used banned APIs: Option - -using System.Diagnostics.CodeAnalysis; - -namespace Microsoft.CodeAnalysis.Options -{ - internal partial class Option2 - { - [return: NotNullIfNotNull(nameof(option))] - public static explicit operator Option?(Option2? option) - { - if (option is null) - { - return null; - } - - return new Option(option.OptionDefinition, option.StorageLocations.As()); - } - } -} diff --git a/src/Workspaces/Core/Portable/Options/OptionChangedEventArgs.cs b/src/Workspaces/Core/Portable/Options/OptionChangedEventArgs.cs index b967e4964066f..64560838baacb 100644 --- a/src/Workspaces/Core/Portable/Options/OptionChangedEventArgs.cs +++ b/src/Workspaces/Core/Portable/Options/OptionChangedEventArgs.cs @@ -8,16 +8,16 @@ namespace Microsoft.CodeAnalysis.Options { internal sealed class OptionChangedEventArgs : EventArgs { - public OptionKey OptionKey { get; } + public OptionKey2 OptionKey { get; } public object? Value { get; } - internal OptionChangedEventArgs(OptionKey optionKey, object? value) + internal OptionChangedEventArgs(OptionKey2 optionKey, object? value) { OptionKey = optionKey; Value = value; } - public IOption Option => OptionKey.Option; + public IOption2 Option => OptionKey.Option; public string? Language => OptionKey.Language; } } diff --git a/src/Workspaces/Core/Portable/Options/OptionKey.cs b/src/Workspaces/Core/Portable/Options/OptionKey.cs index 7a810101412e3..8259974a6f30c 100644 --- a/src/Workspaces/Core/Portable/Options/OptionKey.cs +++ b/src/Workspaces/Core/Portable/Options/OptionKey.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Diagnostics.CodeAnalysis; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Options @@ -19,17 +20,23 @@ namespace Microsoft.CodeAnalysis.Options public OptionKey(IOption option, string? language = null) { + if (option is null) + { + throw new ArgumentNullException(nameof(option)); + } + if (language != null && !option.IsPerLanguage) { throw new ArgumentException(WorkspacesResources.A_language_name_cannot_be_specified_for_this_option); } - else if (language == null && option.IsPerLanguage) + + if (language == null && option.IsPerLanguage) { throw new ArgumentNullException(WorkspacesResources.A_language_name_must_be_specified_for_this_option); } - this.Option = option ?? throw new ArgumentNullException(nameof(option)); - this.Language = language; + Option = option; + Language = language; } public override bool Equals(object? obj) diff --git a/src/Workspaces/Core/Portable/Options/OptionKey2_operators.cs b/src/Workspaces/Core/Portable/Options/OptionKey2_operators.cs deleted file mode 100644 index 1caa3f5ec5bfa..0000000000000 --- a/src/Workspaces/Core/Portable/Options/OptionKey2_operators.cs +++ /dev/null @@ -1,12 +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. - -namespace Microsoft.CodeAnalysis.Options -{ - internal readonly partial struct OptionKey2 - { - public static explicit operator OptionKey(OptionKey2 optionKey) - => new(optionKey.Option, optionKey.Language); - } -} diff --git a/src/Workspaces/Core/Portable/Options/OptionServiceFactory.cs b/src/Workspaces/Core/Portable/Options/OptionServiceFactory.cs deleted file mode 100644 index 074db2ad944ad..0000000000000 --- a/src/Workspaces/Core/Portable/Options/OptionServiceFactory.cs +++ /dev/null @@ -1,33 +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.Composition; -using Microsoft.CodeAnalysis.Host.Mef; - -namespace Microsoft.CodeAnalysis.Options; - -[ExportWorkspaceService(typeof(ILegacyWorkspaceOptionService)), Shared] -internal sealed class LegacyWorkspaceOptionService : ILegacyWorkspaceOptionService -{ - public IGlobalOptionService GlobalOptions { get; } - - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public LegacyWorkspaceOptionService(IGlobalOptionService globalOptionService) - => GlobalOptions = globalOptionService; - - public void RegisterWorkspace(Workspace workspace) - => GlobalOptions.RegisterWorkspace(workspace); - - public void UnregisterWorkspace(Workspace workspace) - => GlobalOptions.UnregisterWorkspace(workspace); - - public object? GetOption(OptionKey key) - => GlobalOptions.GetOption(key); - - public void SetOptions(OptionSet optionSet, IEnumerable optionKeys) - => GlobalOptions.SetOptions(optionSet, optionKeys); -} diff --git a/src/Workspaces/Core/Portable/Options/OptionSet+AnalyzerConfigOptionsImpl.cs b/src/Workspaces/Core/Portable/Options/OptionSet+AnalyzerConfigOptionsImpl.cs deleted file mode 100644 index 85ae75e0479e5..0000000000000 --- a/src/Workspaces/Core/Portable/Options/OptionSet+AnalyzerConfigOptionsImpl.cs +++ /dev/null @@ -1,55 +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.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using Microsoft.CodeAnalysis.CodeStyle; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; - -namespace Microsoft.CodeAnalysis.Options -{ - public abstract partial class OptionSet - { - private sealed class AnalyzerConfigOptionsImpl : StructuredAnalyzerConfigOptions - { - private readonly OptionSet _optionSet; - private readonly IEditorConfigOptionMappingService _optionMappingService; - private readonly string? _language; - - public AnalyzerConfigOptionsImpl(OptionSet optionSet, IEditorConfigOptionMappingService optionMappingService, string? language) - { - _optionSet = optionSet; - _optionMappingService = optionMappingService; - _language = language; - } - - public override NamingStylePreferences GetNamingStylePreferences() - => _optionSet.GetOption(NamingStyleOptions.NamingPreferences, _language); - - public override bool TryGetValue(string key, [NotNullWhen(true)] out string? value) - { - if (!_optionMappingService.TryMapEditorConfigKeyToOption(key, _language, out var storageLocation, out var optionKey)) - { - // There are couple of reasons this assert might fire: - // 1. Attempting to access an option which does not have an IEditorConfigStorageLocation. - // 2. Attempting to access an option which is not exposed from any option provider, i.e. IOptionProvider.Options. - Debug.Fail("Failed to find an .editorconfig entry for the requested key."); - value = null; - return false; - } - - value = storageLocation.GetEditorConfigStringValue(optionKey, _optionSet); - return true; - } - - // no way to enumerate OptionSet - public override IEnumerable Keys - => throw new NotImplementedException(); - } - } -} diff --git a/src/Workspaces/Core/Portable/Options/OptionSet.cs b/src/Workspaces/Core/Portable/Options/OptionSet.cs index 21d985d95a34f..0af5542e67537 100644 --- a/src/Workspaces/Core/Portable/Options/OptionSet.cs +++ b/src/Workspaces/Core/Portable/Options/OptionSet.cs @@ -2,75 +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. -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using Microsoft.CodeAnalysis.Diagnostics; +using System.Diagnostics; +using System.Linq; +using Microsoft.CodeAnalysis.CodeStyle; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Options { - public abstract partial class OptionSet + public abstract partial class OptionSet : IOptionsReader { - private const string NoLanguageSentinel = "\0"; - private static readonly ImmutableDictionary s_emptyAnalyzerConfigOptions = - ImmutableDictionary.Create(StringComparer.Ordinal); - - /// - /// Map from language name to the wrapper. - /// - private ImmutableDictionary _lazyAnalyzerConfigOptions = s_emptyAnalyzerConfigOptions; - - private readonly Func _getOptionCore; + internal static readonly OptionSet Empty = new EmptyOptionSet(); protected OptionSet() { - _getOptionCore = GetOptionCore; } - private protected abstract object? GetOptionCore(OptionKey optionKey); + internal abstract object? GetInternalOptionValue(OptionKey optionKey); /// /// Gets the value of the option, or the default value if not otherwise set. /// public object? GetOption(OptionKey optionKey) - => OptionsHelpers.GetPublicOption(optionKey, _getOptionCore); - - /// - /// Gets the value of the option cast to type , or the default value if not otherwise set. - /// - public T GetOption(OptionKey optionKey) - => OptionsHelpers.GetOption(optionKey, _getOptionCore); - - /// - /// Gets the value of the option, or the default value if not otherwise set. - /// - internal object? GetOption(OptionKey2 optionKey) - => OptionsHelpers.GetOption(optionKey, _getOptionCore); - - /// - /// Gets the value of the option cast to type , or the default value if not otherwise set. - /// - internal T GetOption(OptionKey2 optionKey) - => OptionsHelpers.GetOption(optionKey, _getOptionCore); - - /// - /// Gets the value of the option, or the default value if not otherwise set. - /// - internal T GetOption(Option2 option) - => OptionsHelpers.GetOption(option, _getOptionCore); + { + if (optionKey.Option is IOption2 { Definition.StorageMapping: { } mapping }) + { + return mapping.ToPublicOptionValue(GetInternalOptionValue(new OptionKey(mapping.InternalOption, optionKey.Language))); + } + + var result = GetInternalOptionValue(optionKey); + Debug.Assert(IsPublicOptionValue(result)); + return result; + } /// /// Gets the value of the option, or the default value if not otherwise set. /// - internal T GetOption(PerLanguageOption2 option, string? language) - => OptionsHelpers.GetOption(option, language, _getOptionCore); + public T GetOption(OptionKey optionKey) + => (T)GetOption(optionKey)!; #pragma warning disable RS0030 // Do not used banned APIs: PerLanguageOption /// /// Gets the value of the option, or the default value if not otherwise set. /// public T GetOption(Option option) - => OptionsHelpers.GetOption(new OptionKey(option), _getOptionCore); + => GetOption(new OptionKey(option)); /// /// Creates a new that contains the changed value. @@ -82,7 +57,7 @@ public OptionSet WithChangedOption(Option option, T value) /// Gets the value of the option, or the default value if not otherwise set. /// public T GetOption(PerLanguageOption option, string? language) - => OptionsHelpers.GetOption(new OptionKey(option, language), _getOptionCore); + => GetOption(new OptionKey(option, language)); /// /// Creates a new that contains the changed value. @@ -94,38 +69,37 @@ public OptionSet WithChangedOption(PerLanguageOption option, string? langu /// /// Creates a new that contains the changed value. /// - public abstract OptionSet WithChangedOption(OptionKey optionAndLanguage, object? value); + public virtual OptionSet WithChangedOption(OptionKey optionAndLanguage, object? value) + { + if (optionAndLanguage.Option is IOption2 { Definition.StorageMapping: { } mapping }) + { + var mappedOptionKey = new OptionKey(mapping.InternalOption, optionAndLanguage.Language); + var currentValue = GetInternalOptionValue(mappedOptionKey); + return WithChangedOptionInternal(mappedOptionKey, mapping.UpdateInternalOptionValue(currentValue, value)); + } + + return WithChangedOptionInternal(optionAndLanguage, value); + } - /// - /// Creates a new that contains the changed value. - /// - internal OptionSet WithChangedOption(OptionKey2 optionAndLanguage, object? value) - => WithChangedOption((OptionKey)optionAndLanguage, value); + internal virtual OptionSet WithChangedOptionInternal(OptionKey optionKey, object? internalValue) + => throw ExceptionUtilities.Unreachable(); + + bool IOptionsReader.TryGetOption(OptionKey2 optionKey, out T value) + { + value = (T)GetInternalOptionValue(new OptionKey(optionKey.Option, optionKey.Language))!; + return true; + } /// - /// Creates a new that contains the changed value. + /// Checks if the value is an internal representation -- does not cover all cases, just code style options. /// - internal OptionSet WithChangedOption(Option2 option, T value) - => WithChangedOption(new OptionKey(option), value); + internal static bool IsInternalOptionValue(object? value) + => value is not ICodeStyleOption codeStyle || ReferenceEquals(codeStyle, codeStyle.AsInternalCodeStyleOption()); /// - /// Creates a new that contains the changed value. + /// Checks if the value is an public representation -- does not cover all cases, just code style options. /// - internal OptionSet WithChangedOption(PerLanguageOption2 option, string? language, T value) - => WithChangedOption(new OptionKey(option, language), value); - - internal AnalyzerConfigOptions AsAnalyzerConfigOptions(IEditorConfigOptionMappingService optionMappingService, string? language) - { - return ImmutableInterlocked.GetOrAdd( - ref _lazyAnalyzerConfigOptions, - language ?? NoLanguageSentinel, - (string language, (OptionSet self, IEditorConfigOptionMappingService mapping) arg) => arg.self.CreateAnalyzerConfigOptions(arg.mapping, (object)language == NoLanguageSentinel ? null : language), - (this, optionMappingService)); - } - - internal abstract IEnumerable GetChangedOptions(OptionSet optionSet); - - private protected virtual AnalyzerConfigOptions CreateAnalyzerConfigOptions(IEditorConfigOptionMappingService optionMappingService, string? language) - => new AnalyzerConfigOptionsImpl(this, optionMappingService, language); + internal static bool IsPublicOptionValue(object? value) + => value is not ICodeStyleOption codeStyle || ReferenceEquals(codeStyle, codeStyle.AsPublicCodeStyleOption()); } } diff --git a/src/Workspaces/Core/Portable/Options/OptionValueSet.cs b/src/Workspaces/Core/Portable/Options/OptionValueSet.cs deleted file mode 100644 index 83a0dda17bed3..0000000000000 --- a/src/Workspaces/Core/Portable/Options/OptionValueSet.cs +++ /dev/null @@ -1,29 +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; - -namespace Microsoft.CodeAnalysis.Options -{ - internal sealed class OptionValueSet : OptionSet - { - public static readonly OptionValueSet Empty = new(ImmutableDictionary.Empty); - - private readonly ImmutableDictionary _values; - - public OptionValueSet(ImmutableDictionary values) - => _values = values; - - private protected override object? GetOptionCore(OptionKey optionKey) - => _values.TryGetValue(optionKey, out var value) ? value : optionKey.Option.DefaultValue; - - public override OptionSet WithChangedOption(OptionKey optionAndLanguage, object? value) - => new OptionValueSet(_values.SetItem(optionAndLanguage, value)); - - internal override IEnumerable GetChangedOptions(OptionSet optionSet) - => throw new NotSupportedException(); - } -} diff --git a/src/Workspaces/Core/Portable/Options/OptionsExtensions.cs b/src/Workspaces/Core/Portable/Options/OptionsExtensions.cs deleted file mode 100644 index ef730d95bda7b..0000000000000 --- a/src/Workspaces/Core/Portable/Options/OptionsExtensions.cs +++ /dev/null @@ -1,38 +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. - -#pragma warning disable RS0030 // Do not used banned APIs: Option, PerLanguageOption - -using Microsoft.CodeAnalysis.CodeStyle; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.Options -{ - internal static class OptionsExtensions - { - public static Option> ToPublicOption(this Option2> option) - { - RoslynDebug.Assert(option != null); - - return new Option>( - option.Feature, - option.Group, - option.Name, - defaultValue: new CodeStyleOption(option.DefaultValue), - option.StorageLocations.As()); - } - - public static PerLanguageOption> ToPublicOption(this PerLanguageOption2> option) - { - RoslynDebug.Assert(option != null); - - return new PerLanguageOption>( - option.Feature, - option.Group, - option.Name, - defaultValue: new CodeStyleOption(option.DefaultValue), - option.StorageLocations.As()); - } - } -} diff --git a/src/Workspaces/Core/Portable/Options/OptionsHelpers.cs b/src/Workspaces/Core/Portable/Options/OptionsHelpers.cs deleted file mode 100644 index 0d42129d2f2a6..0000000000000 --- a/src/Workspaces/Core/Portable/Options/OptionsHelpers.cs +++ /dev/null @@ -1,43 +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 Microsoft.CodeAnalysis.CodeStyle; - -namespace Microsoft.CodeAnalysis.Options -{ - internal static class OptionsHelpers - { - public static T GetOption(Option2 option, Func getOption) - => GetOption(new OptionKey(option), getOption); - - public static T GetOption(PerLanguageOption2 option, string? language, Func getOption) - => GetOption(new OptionKey(option, language), getOption); - - public static T GetOption(OptionKey2 optionKey, Func getOption) - => GetOption(new OptionKey(optionKey.Option, optionKey.Language), getOption); - - public static T GetOption(OptionKey optionKey, Func getOption) - { - var value = getOption(optionKey); - if (value is ICodeStyleOption codeStyleOption) - { - return (T)codeStyleOption.AsCodeStyleOption(); - } - - return (T)value!; - } - - public static object? GetPublicOption(OptionKey optionKey, Func getOption) - { - var value = getOption(optionKey); - if (value is ICodeStyleOption codeStyleOption) - { - return codeStyleOption.AsPublicCodeStyleOption(); - } - - return value; - } - } -} diff --git a/src/Workspaces/Core/Portable/Options/PerLanguageOption.cs b/src/Workspaces/Core/Portable/Options/PerLanguageOption.cs index a935e8a6a669b..f775ba1401caa 100644 --- a/src/Workspaces/Core/Portable/Options/PerLanguageOption.cs +++ b/src/Workspaces/Core/Portable/Options/PerLanguageOption.cs @@ -6,22 +6,18 @@ using System; using System.Collections.Immutable; +using System.Diagnostics; +using System.Linq; namespace Microsoft.CodeAnalysis.Options { /// - public class PerLanguageOption : IPerLanguageValuedOption + public class PerLanguageOption : IPublicOption { private readonly OptionDefinition _optionDefinition; - /// - public string Feature => _optionDefinition.Feature; - - /// - internal OptionGroup Group => _optionDefinition.Group; - - /// - public string Name => _optionDefinition.Name; + public string Feature { get; } + public string Name { get; } /// public Type Type => _optionDefinition.Type; @@ -29,7 +25,6 @@ public class PerLanguageOption : IPerLanguageValuedOption /// public T DefaultValue => (T)_optionDefinition.DefaultValue!; - /// public ImmutableArray StorageLocations { get; } public PerLanguageOption(string feature, string name, T defaultValue) @@ -37,7 +32,9 @@ public PerLanguageOption(string feature, string name, T defaultValue) OptionGroup.Default, name ?? throw new ArgumentNullException(nameof(name)), defaultValue, - storageLocations: ImmutableArray.Empty) + storageLocations: ImmutableArray.Empty, + storageMapping: null, + isEditorConfigOption: false) { } @@ -46,32 +43,45 @@ public PerLanguageOption(string feature, string name, T defaultValue, params Opt OptionGroup.Default, name ?? throw new ArgumentNullException(nameof(name)), defaultValue, - (storageLocations ?? throw new ArgumentNullException(nameof(storageLocations))).ToImmutableArray()) + PublicContract.RequireNonNullItems(storageLocations, nameof(storageLocations)).ToImmutableArray(), + storageMapping: null, + isEditorConfigOption: false) { + // should not be used internally to create options + Debug.Assert(storageLocations.All(l => l is not IEditorConfigValueSerializer)); } - internal PerLanguageOption(string? feature, OptionGroup group, string? name, T defaultValue, ImmutableArray storageLocations) - : this(new OptionDefinition(feature, group, name, storageLocations.GetOptionConfigName(feature, name), defaultValue, typeof(T)), storageLocations) + private PerLanguageOption( + string feature, + OptionGroup group, + string name, + T defaultValue, + ImmutableArray storageLocations, + OptionStorageMapping? storageMapping, + bool isEditorConfigOption) + : this(new OptionDefinition(defaultValue, EditorConfigValueSerializer.Unsupported, group, feature + "_" + name, storageMapping, isEditorConfigOption), feature, name, storageLocations) { } - internal PerLanguageOption(OptionDefinition optionDefinition, ImmutableArray storageLocations) + internal PerLanguageOption(OptionDefinition optionDefinition, string feature, string name, ImmutableArray storageLocations) { + Feature = feature; + Name = name; _optionDefinition = optionDefinition; StorageLocations = storageLocations; } - OptionDefinition IOption2.OptionDefinition => _optionDefinition; - - OptionGroup IOptionWithGroup.Group => this.Group; + OptionDefinition IOption2.Definition => _optionDefinition; object? IOption.DefaultValue => this.DefaultValue; + IPublicOption? IOption2.PublicOption => null; + bool IOption.IsPerLanguage => true; bool IEquatable.Equals(IOption2? other) => Equals(other); - public override string ToString() => _optionDefinition.PublicOptionDefinitionToString(); + public override string ToString() => this.PublicOptionDefinitionToString(); public override int GetHashCode() => _optionDefinition.GetHashCode(); @@ -84,7 +94,7 @@ private bool Equals(IOption2? other) return true; } - return other is not null && _optionDefinition.PublicOptionDefinitionEquals(other.OptionDefinition); + return other is not null && this.PublicOptionDefinitionEquals(other); } } } diff --git a/src/Workspaces/Core/Portable/Options/PerLanguageOption2_operators.cs b/src/Workspaces/Core/Portable/Options/PerLanguageOption2_operators.cs deleted file mode 100644 index c23ba4ab35a8f..0000000000000 --- a/src/Workspaces/Core/Portable/Options/PerLanguageOption2_operators.cs +++ /dev/null @@ -1,24 +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. - -#pragma warning disable RS0030 // Do not used banned APIs: PerLanguageOption - -using System.Diagnostics.CodeAnalysis; - -namespace Microsoft.CodeAnalysis.Options -{ - internal partial class PerLanguageOption2 - { - [return: NotNullIfNotNull(nameof(option))] - public static explicit operator PerLanguageOption?(PerLanguageOption2? option) - { - if (option is null) - { - return null; - } - - return new PerLanguageOption(option.OptionDefinition, option.StorageLocations.As()); - } - } -} diff --git a/src/Workspaces/Core/Portable/Options/Providers/ExportOptionProviderAttribute.cs b/src/Workspaces/Core/Portable/Options/Providers/ExportOptionProviderAttribute.cs deleted file mode 100644 index 454999bb0e848..0000000000000 --- a/src/Workspaces/Core/Portable/Options/Providers/ExportOptionProviderAttribute.cs +++ /dev/null @@ -1,49 +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.Composition; - -namespace Microsoft.CodeAnalysis.Options.Providers -{ - [MetadataAttribute] - [AttributeUsage(AttributeTargets.Class)] - internal abstract class ExportOptionProviderAttribute : ExportAttribute - { - /// - /// Optional source language for language specific option providers. See . - /// This will be empty string for language agnostic option providers. - /// - public string Language { get; } - - /// - /// True if the option is a client global option provided by . - /// - public bool IsGlobal { get; } - - public ExportOptionProviderAttribute(string language, bool isGlobal) - : base(typeof(IOptionProvider)) - { - Language = language; - IsGlobal = isGlobal; - } - } - - /// - /// Options that are part of the solution snapshot. - /// Some of these options may be configurable per document via editorconfig. - /// - internal sealed class ExportSolutionOptionProviderAttribute : ExportOptionProviderAttribute - { - public ExportSolutionOptionProviderAttribute() - : this(language: string.Empty) - { - } - - public ExportSolutionOptionProviderAttribute(string language) - : base(language, isGlobal: false) - { - } - } -} diff --git a/src/Workspaces/Core/Portable/Options/Providers/IOptionProvider.cs b/src/Workspaces/Core/Portable/Options/Providers/IOptionProvider.cs deleted file mode 100644 index d663875cb4f75..0000000000000 --- a/src/Workspaces/Core/Portable/Options/Providers/IOptionProvider.cs +++ /dev/null @@ -1,13 +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; - -namespace Microsoft.CodeAnalysis.Options.Providers -{ - internal interface IOptionProvider - { - ImmutableArray Options { get; } - } -} diff --git a/src/Workspaces/Core/Portable/Options/SolutionOptionSet.cs b/src/Workspaces/Core/Portable/Options/SolutionOptionSet.cs index 78c461b8b7ca8..243b4e83b2ed0 100644 --- a/src/Workspaces/Core/Portable/Options/SolutionOptionSet.cs +++ b/src/Workspaces/Core/Portable/Options/SolutionOptionSet.cs @@ -2,17 +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. -using System; -using System.Collections; using System.Collections.Generic; using System.Collections.Immutable; -using System.Diagnostics; using System.Linq; -using System.Threading; using Microsoft.CodeAnalysis.CodeStyle; -using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; -using Microsoft.CodeAnalysis.PooledObjects; -using Microsoft.CodeAnalysis.Remote; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Options @@ -24,10 +17,10 @@ namespace Microsoft.CodeAnalysis.Options /// internal sealed class SolutionOptionSet : OptionSet { - private readonly ILegacyWorkspaceOptionService _globalOptions; + private readonly ILegacyGlobalOptionService _legacyGlobalOptions; /// - /// Cached values read from global options. + /// Cached values read from global options. Stores internal values of options. /// private ImmutableDictionary _values; @@ -37,72 +30,58 @@ internal sealed class SolutionOptionSet : OptionSet private readonly ImmutableHashSet _changedOptionKeys; private SolutionOptionSet( - ILegacyWorkspaceOptionService globalOptions, + ILegacyGlobalOptionService globalOptions, ImmutableDictionary values, ImmutableHashSet changedOptionKeys) { - _globalOptions = globalOptions; + _legacyGlobalOptions = globalOptions; _values = values; _changedOptionKeys = changedOptionKeys; } - internal SolutionOptionSet(ILegacyWorkspaceOptionService globalOptions) + internal SolutionOptionSet(ILegacyGlobalOptionService globalOptions) : this(globalOptions, values: ImmutableDictionary.Empty, changedOptionKeys: ImmutableHashSet.Empty) { } [PerformanceSensitive("https://github.com/dotnet/roslyn/issues/30819", AllowLocks = false)] - private protected override object? GetOptionCore(OptionKey optionKey) + internal override object? GetInternalOptionValue(OptionKey optionKey) { if (_values.TryGetValue(optionKey, out var value)) { - return value is ICodeStyleOption codeStyleOption ? codeStyleOption.AsPublicCodeStyleOption() : value; + return value; } - value = _globalOptions.GetOption(optionKey); + value = (optionKey.Option is IOption2 internallyDefinedOption) + ? _legacyGlobalOptions.GlobalOptions.GetOption(new OptionKey2(internallyDefinedOption, optionKey.Language)) + : _legacyGlobalOptions.GetExternallyDefinedOption(optionKey); + return ImmutableInterlocked.GetOrAdd(ref _values, optionKey, value); } - public override OptionSet WithChangedOption(OptionKey optionKey, object? value) + internal override OptionSet WithChangedOptionInternal(OptionKey optionKey, object? internalValue) { // Make sure we first load this in current optionset - var currentValue = GetOption(optionKey); + var currentInternalValue = GetInternalOptionValue(optionKey); // Check if the new value is the same as the current value. - if (Equals(value, currentValue)) + if (Equals(internalValue, currentInternalValue)) { // Return a cloned option set as the public API 'WithChangedOption' guarantees a new option set is returned. - return new SolutionOptionSet(_globalOptions, _values, _changedOptionKeys); + return new SolutionOptionSet(_legacyGlobalOptions, _values, _changedOptionKeys); } return new SolutionOptionSet( - _globalOptions, - _values.SetItem(optionKey, value), + _legacyGlobalOptions, + _values.SetItem(optionKey, internalValue), _changedOptionKeys.Add(optionKey)); } - /// - /// Gets a list of all the options that were changed. - /// - internal IEnumerable GetChangedOptions() - => _changedOptionKeys; - - internal override IEnumerable GetChangedOptions(OptionSet? optionSet) + internal (ImmutableArray> internallyDefined, ImmutableArray> externallyDefined) GetChangedOptions() { - if (optionSet == this) - { - yield break; - } - - foreach (var key in GetChangedOptions()) - { - var currentValue = optionSet?.GetOption(key); - var changedValue = this.GetOption(key); - if (!object.Equals(currentValue, changedValue)) - { - yield return key; - } - } + var internallyDefined = _changedOptionKeys.Where(key => key.Option is IOption2).SelectAsArray(key => KeyValuePairUtil.Create(new OptionKey2((IOption2)key.Option, key.Language), _values[key])); + var externallyDefined = _changedOptionKeys.Where(key => key.Option is not IOption2).SelectAsArray(key => KeyValuePairUtil.Create(key, _values[key])); + return (internallyDefined, externallyDefined); } } } diff --git a/src/Workspaces/Core/Portable/OrganizeImports/OrganizeImportsOptions.cs b/src/Workspaces/Core/Portable/OrganizeImports/OrganizeImportsOptions.cs index ef7c3fd9dff8a..c4490e506895d 100644 --- a/src/Workspaces/Core/Portable/OrganizeImports/OrganizeImportsOptions.cs +++ b/src/Workspaces/Core/Portable/OrganizeImports/OrganizeImportsOptions.cs @@ -9,6 +9,7 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.OrganizeImports; @@ -32,22 +33,22 @@ internal interface OrganizeImportsOptionsProvider : OptionsProvider GetOrganizeImportsOptionsAsync(this Document document, OrganizeImportsOptions? fallbackOptions, CancellationToken cancellationToken) { var configOptions = await document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); - return configOptions.GetOrganizeImportsOptions(fallbackOptions); + return configOptions.GetOrganizeImportsOptions(document.Project.Language, fallbackOptions); } public static async ValueTask GetOrganizeImportsOptionsAsync(this Document document, OrganizeImportsOptionsProvider fallbackOptionsProvider, CancellationToken cancellationToken) diff --git a/src/Workspaces/Core/Portable/PublicAPI.Shipped.txt b/src/Workspaces/Core/Portable/PublicAPI.Shipped.txt index c5a4d32934b1e..49ca3ac2c9249 100644 --- a/src/Workspaces/Core/Portable/PublicAPI.Shipped.txt +++ b/src/Workspaces/Core/Portable/PublicAPI.Shipped.txt @@ -1393,7 +1393,6 @@ override Microsoft.CodeAnalysis.FileTextLoader.LoadTextAndVersionAsync(Microsoft override Microsoft.CodeAnalysis.FindSymbols.ReferenceLocation.Equals(object obj) -> bool override Microsoft.CodeAnalysis.FindSymbols.ReferenceLocation.GetHashCode() -> int override Microsoft.CodeAnalysis.Host.Mef.MefHostServices.CreateWorkspaceServices(Microsoft.CodeAnalysis.Workspace workspace) -> Microsoft.CodeAnalysis.Host.HostWorkspaceServices -override Microsoft.CodeAnalysis.Options.DocumentOptionSet.WithChangedOption(Microsoft.CodeAnalysis.Options.OptionKey optionAndLanguage, object value) -> Microsoft.CodeAnalysis.Options.OptionSet override Microsoft.CodeAnalysis.Options.Option.Equals(object obj) -> bool override Microsoft.CodeAnalysis.Options.Option.GetHashCode() -> int override Microsoft.CodeAnalysis.Options.Option.ToString() -> string diff --git a/src/Workspaces/Core/Portable/PublicAPI.Unshipped.txt b/src/Workspaces/Core/Portable/PublicAPI.Unshipped.txt index fc0befde8d85d..2749267b4df93 100644 --- a/src/Workspaces/Core/Portable/PublicAPI.Unshipped.txt +++ b/src/Workspaces/Core/Portable/PublicAPI.Unshipped.txt @@ -56,5 +56,8 @@ static Microsoft.CodeAnalysis.LoadTextOptions.operator !=(Microsoft.CodeAnalysis static Microsoft.CodeAnalysis.LoadTextOptions.operator ==(Microsoft.CodeAnalysis.LoadTextOptions left, Microsoft.CodeAnalysis.LoadTextOptions right) -> bool override Microsoft.CodeAnalysis.FileTextLoader.LoadTextAndVersionAsync(Microsoft.CodeAnalysis.LoadTextOptions options, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task *REMOVED*abstract Microsoft.CodeAnalysis.TextLoader.LoadTextAndVersionAsync(Microsoft.CodeAnalysis.Workspace workspace, Microsoft.CodeAnalysis.DocumentId documentId, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task +virtual Microsoft.CodeAnalysis.Options.OptionSet.WithChangedOption(Microsoft.CodeAnalysis.Options.OptionKey optionAndLanguage, object value) -> Microsoft.CodeAnalysis.Options.OptionSet +*REMOVED*abstract Microsoft.CodeAnalysis.Options.OptionSet.WithChangedOption(Microsoft.CodeAnalysis.Options.OptionKey optionAndLanguage, object value) -> Microsoft.CodeAnalysis.Options.OptionSet +*REMOVED*override Microsoft.CodeAnalysis.Options.DocumentOptionSet.WithChangedOption(Microsoft.CodeAnalysis.Options.OptionKey optionAndLanguage, object value) -> Microsoft.CodeAnalysis.Options.OptionSet virtual Microsoft.CodeAnalysis.TextLoader.LoadTextAndVersionAsync(Microsoft.CodeAnalysis.LoadTextOptions options, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task virtual Microsoft.CodeAnalysis.TextLoader.LoadTextAndVersionAsync(Microsoft.CodeAnalysis.Workspace workspace, Microsoft.CodeAnalysis.DocumentId documentId, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task diff --git a/src/Workspaces/Core/Portable/Recommendations/RecommendationOptions.cs b/src/Workspaces/Core/Portable/Recommendations/RecommendationOptions.cs index 41057a02ca771..72b53702c90d8 100644 --- a/src/Workspaces/Core/Portable/Recommendations/RecommendationOptions.cs +++ b/src/Workspaces/Core/Portable/Recommendations/RecommendationOptions.cs @@ -10,15 +10,20 @@ namespace Microsoft.CodeAnalysis.Recommendations; #pragma warning disable RS0030 // Do not used banned APIs: PerLanguageOption public static class RecommendationOptions { - public static PerLanguageOption HideAdvancedMembers { get; } = (PerLanguageOption)RecommendationOptions2.HideAdvancedMembers; - public static PerLanguageOption FilterOutOfScopeLocals { get; } = (PerLanguageOption)RecommendationOptions2.FilterOutOfScopeLocals; + public static PerLanguageOption HideAdvancedMembers { get; } = RecommendationOptions2.HideAdvancedMembers.ToPublicOption(); + public static PerLanguageOption FilterOutOfScopeLocals { get; } = RecommendationOptions2.FilterOutOfScopeLocals.ToPublicOption(); } #pragma warning restore internal static class RecommendationOptions2 { - public static readonly PerLanguageOption2 HideAdvancedMembers = new("RecommendationOptions", "HideAdvancedMembers", RecommendationServiceOptions.Default.HideAdvancedMembers); - public static readonly PerLanguageOption2 FilterOutOfScopeLocals = new("RecommendationOptions", "FilterOutOfScopeLocals", RecommendationServiceOptions.Default.FilterOutOfScopeLocals); + public static readonly PerLanguageOption2 HideAdvancedMembers = new PerLanguageOption2( + "RecommendationOptions_HideAdvancedMembers", RecommendationServiceOptions.Default.HideAdvancedMembers) + .WithPublicOption("RecommendationOptions", "HideAdvancedMembers"); + + public static readonly PerLanguageOption2 FilterOutOfScopeLocals = new PerLanguageOption2( + "RecommendationOptions_FilterOutOfScopeLocals", RecommendationServiceOptions.Default.FilterOutOfScopeLocals) + .WithPublicOption("RecommendationOptions", "FilterOutOfScopeLocals"); } [DataContract] diff --git a/src/Workspaces/Core/Portable/Shared/TestHooks/TaskExtensions.cs b/src/Workspaces/Core/Portable/Shared/TestHooks/TaskExtensions.cs index ac2fb3cb78fd3..b58488f812ff3 100644 --- a/src/Workspaces/Core/Portable/Shared/TestHooks/TaskExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/TestHooks/TaskExtensions.cs @@ -4,14 +4,13 @@ using System; using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Shared.TestHooks { - internal static class TaskExtensions + internal static partial class TaskExtensions { [SuppressMessage("Style", "VSTHRD200:Use \"Async\" suffix for async methods", Justification = "This is a Task wrapper, not an asynchronous method.")] public static Task CompletesAsyncOperation(this Task task, IAsyncToken asyncToken) @@ -46,122 +45,5 @@ static Task CompletesTrackingOperationSlow(Task task, IDisposable token) TaskScheduler.Default); } } - - // Following code is copied from Microsoft.VisualStudio.Threading.TplExtensions (renamed to avoid ambiguity) - // https://github.com/microsoft/vs-threading/blob/main/src/Microsoft.VisualStudio.Threading/TplExtensions.cs - - /// - /// Returns an awaitable for the specified task that will never throw, even if the source task - /// faults or is canceled. - /// - /// The task whose completion should signal the completion of the returned awaitable. - /// if set to true the continuation will be scheduled on the caller's context; false to always execute the continuation on the threadpool. - /// An awaitable. - public static NoThrowTaskAwaitable NoThrowAwaitableInternal(this Task task, bool captureContext = true) - { - return new NoThrowTaskAwaitable(task, captureContext); - } - - /// - /// An awaitable that wraps a task and never throws an exception when waited on. - /// - public readonly struct NoThrowTaskAwaitable - { - /// - /// The task. - /// - private readonly Task _task; - - /// - /// A value indicating whether the continuation should be scheduled on the current sync context. - /// - private readonly bool _captureContext; - - /// - /// Initializes a new instance of the struct. - /// - /// The task. - /// Whether the continuation should be scheduled on the current sync context. - public NoThrowTaskAwaitable(Task task, bool captureContext) - { - Contract.ThrowIfNull(task, nameof(task)); - _task = task; - _captureContext = captureContext; - } - - /// - /// Gets the awaiter. - /// - /// The awaiter. - public NoThrowTaskAwaiter GetAwaiter() - { - return new NoThrowTaskAwaiter(_task, _captureContext); - } - } - - /// - /// An awaiter that wraps a task and never throws an exception when waited on. - /// - public readonly struct NoThrowTaskAwaiter : ICriticalNotifyCompletion - { - /// - /// The task. - /// - private readonly Task _task; - - /// - /// A value indicating whether the continuation should be scheduled on the current sync context. - /// - private readonly bool _captureContext; - - /// - /// Initializes a new instance of the struct. - /// - /// The task. - /// if set to true [capture context]. - public NoThrowTaskAwaiter(Task task, bool captureContext) - { - Contract.ThrowIfNull(task, nameof(task)); - _task = task; - _captureContext = captureContext; - } - - /// - /// Gets a value indicating whether the task has completed. - /// - public bool IsCompleted - { - get { return _task.IsCompleted; } - } - - /// - /// Schedules a delegate for execution at the conclusion of a task's execution. - /// - /// The action. - public void OnCompleted(Action continuation) - { - _task.ConfigureAwait(_captureContext).GetAwaiter().OnCompleted(continuation); - } - - /// - /// Schedules a delegate for execution at the conclusion of a task's execution - /// without capturing the ExecutionContext. - /// - /// The action. - public void UnsafeOnCompleted(Action continuation) - { - _task.ConfigureAwait(_captureContext).GetAwaiter().UnsafeOnCompleted(continuation); - } - - /// - /// Does nothing. - /// -#pragma warning disable CA1822 // Mark members as static - public void GetResult() -#pragma warning restore CA1822 // Mark members as static - { - // Never throw here. - } - } } } diff --git a/src/Workspaces/Core/Portable/Simplification/AbstractSimplificationService.cs b/src/Workspaces/Core/Portable/Simplification/AbstractSimplificationService.cs index 671e3bd0bacd3..6223e66c5d522 100644 --- a/src/Workspaces/Core/Portable/Simplification/AbstractSimplificationService.cs +++ b/src/Workspaces/Core/Portable/Simplification/AbstractSimplificationService.cs @@ -13,6 +13,7 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Internal.Log; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -38,7 +39,7 @@ protected AbstractSimplificationService(ImmutableArray reducers protected abstract bool NodeRequiresNonSpeculativeSemanticModel(SyntaxNode node); public abstract SimplifierOptions DefaultOptions { get; } - public abstract SimplifierOptions GetSimplifierOptions(AnalyzerConfigOptions options, SimplifierOptions? fallbackOptions); + public abstract SimplifierOptions GetSimplifierOptions(IOptionsReader options, SimplifierOptions? fallbackOptions); protected virtual SyntaxNode TransformReducedNode(SyntaxNode reducedNode, SyntaxNode originalNode) => reducedNode; diff --git a/src/Workspaces/Core/Portable/Simplification/SimplificationOptionProvider.cs b/src/Workspaces/Core/Portable/Simplification/SimplificationOptionProvider.cs deleted file mode 100644 index 447b5355c20ff..0000000000000 --- a/src/Workspaces/Core/Portable/Simplification/SimplificationOptionProvider.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; -using System.Collections.Immutable; -using System.Composition; -using Microsoft.CodeAnalysis.CodeStyle; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Options.Providers; - -namespace Microsoft.CodeAnalysis.Simplification -{ - [ExportSolutionOptionProvider, Shared] - internal class SimplificationOptionsProvider : IOptionProvider - { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public SimplificationOptionsProvider() - { - } - - public ImmutableArray Options { get; } = ImmutableArray.Create( - NamingStyleOptions.NamingPreferences); - } -} diff --git a/src/Workspaces/Core/Portable/Simplification/Simplifier.cs b/src/Workspaces/Core/Portable/Simplification/Simplifier.cs index c2fd4c8b91cca..ebf540392a665 100644 --- a/src/Workspaces/Core/Portable/Simplification/Simplifier.cs +++ b/src/Workspaces/Core/Portable/Simplification/Simplifier.cs @@ -253,11 +253,9 @@ internal static async Task ReduceAsync( #pragma warning disable RS0030 // Do not used banned APIs (backwards compatibility) internal static async Task GetOptionsAsync(Document document, OptionSet? optionSet, CancellationToken cancellationToken) { - var services = document.Project.Solution.Services; - var optionService = services.GetRequiredService(); - var configOptionSet = (optionSet ?? await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false)).AsAnalyzerConfigOptions(optionService, document.Project.Language); - var simplificationService = services.GetRequiredLanguageService(document.Project.Language); - return simplificationService.GetSimplifierOptions(configOptionSet, fallbackOptions: null); + optionSet ??= await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); + var simplificationService = document.Project.Solution.Services.GetRequiredLanguageService(document.Project.Language); + return simplificationService.GetSimplifierOptions(optionSet, fallbackOptions: null); } #pragma warning restore } diff --git a/src/Workspaces/Core/Portable/SolutionCrawler/ISolutionCrawlerRegistrationService.cs b/src/Workspaces/Core/Portable/SolutionCrawler/ISolutionCrawlerRegistrationService.cs index 22abe33b8db81..b7e32630fb5ca 100644 --- a/src/Workspaces/Core/Portable/SolutionCrawler/ISolutionCrawlerRegistrationService.cs +++ b/src/Workspaces/Core/Portable/SolutionCrawler/ISolutionCrawlerRegistrationService.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.Host; namespace Microsoft.CodeAnalysis.SolutionCrawler @@ -14,6 +12,11 @@ namespace Microsoft.CodeAnalysis.SolutionCrawler internal interface ISolutionCrawlerRegistrationService : IWorkspaceService { void Register(Workspace workspace); + + /// + /// Unregisters solution crawler for given . + /// No-op if never registered or already unregistered. + /// void Unregister(Workspace workspace, bool blockingShutdown = false); void AddAnalyzerProvider(IIncrementalAnalyzerProvider provider, IncrementalAnalyzerProviderMetadata metadata); diff --git a/src/Workspaces/Core/Portable/TaskList/TaskListItem.cs b/src/Workspaces/Core/Portable/TaskList/TaskListItem.cs index 1f9580d6a1e8f..cf3dff9dfeac3 100644 --- a/src/Workspaces/Core/Portable/TaskList/TaskListItem.cs +++ b/src/Workspaces/Core/Portable/TaskList/TaskListItem.cs @@ -6,53 +6,15 @@ using System.Runtime.Serialization; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.TaskList -{ - /// - /// Serialization type used to pass information to/from OOP and VS. - /// - [DataContract] - internal readonly struct TaskListItem : IEquatable - { - [DataMember(Order = 0)] - public readonly int Priority; - - [DataMember(Order = 1)] - public readonly string Message; - - [DataMember(Order = 2)] - public readonly DocumentId DocumentId; - - [DataMember(Order = 3)] - public readonly FileLinePositionSpan Span; - - [DataMember(Order = 4)] - public readonly FileLinePositionSpan MappedSpan; - - public TaskListItem(int priority, string message, DocumentId documentId, FileLinePositionSpan span, FileLinePositionSpan mappedSpan) - { - Priority = priority; - Message = message; - DocumentId = documentId; - Span = span; - MappedSpan = mappedSpan; - } - - public override bool Equals(object? obj) - => obj is TaskListItem other && Equals(other); - - public override int GetHashCode() - => Hash.Combine(this.DocumentId, - Hash.Combine(this.Priority, - Hash.Combine(this.Message, this.Span.Span.GetHashCode()))); - - public override string ToString() - => $"{Priority} {Message} {MappedSpan.Path ?? ""} ({MappedSpan.StartLinePosition.Line}, {MappedSpan.StartLinePosition.Character}) [original: {Span.Path ?? ""} ({Span.StartLinePosition.Line}, {Span.StartLinePosition.Character})"; - - public bool Equals(TaskListItem right) - => DocumentId == right.DocumentId && - Priority == right.Priority && - Message == right.Message && - Span.Span == right.Span.Span; - } -} +namespace Microsoft.CodeAnalysis.TaskList; + +/// +/// Serialization type used to pass information to/from OOP and VS. +/// +[DataContract] +internal readonly record struct TaskListItem( + [property: DataMember(Order = 0)] TaskListItemPriority Priority, + [property: DataMember(Order = 1)] string Message, + [property: DataMember(Order = 2)] DocumentId DocumentId, + [property: DataMember(Order = 3)] FileLinePositionSpan Span, + [property: DataMember(Order = 4)] FileLinePositionSpan MappedSpan); diff --git a/src/Workspaces/Core/Portable/TaskList/TaskListItemDescriptor.cs b/src/Workspaces/Core/Portable/TaskList/TaskListItemDescriptor.cs index 81c2547a65273..4e15badad56ec 100644 --- a/src/Workspaces/Core/Portable/TaskList/TaskListItemDescriptor.cs +++ b/src/Workspaces/Core/Portable/TaskList/TaskListItemDescriptor.cs @@ -9,6 +9,13 @@ namespace Microsoft.CodeAnalysis.TaskList { + internal enum TaskListItemPriority + { + Low, + Medium, + High, + } + /// /// Description of a TODO comment type to find in a user's comments. /// @@ -18,9 +25,9 @@ internal readonly struct TaskListItemDescriptor [DataMember(Order = 0)] public string Text { get; } [DataMember(Order = 1)] - public int Priority { get; } + public TaskListItemPriority Priority { get; } - public TaskListItemDescriptor(string text, int priority) + public TaskListItemDescriptor(string text, TaskListItemPriority priority) { Text = text; Priority = priority; @@ -34,8 +41,25 @@ public static ImmutableArray Parse(ImmutableArray TaskListItemPriority.Low, + 2 => TaskListItemPriority.Medium, + 3 => TaskListItemPriority.High, + _ => TaskListItemPriority.Medium, + }; result.Add(new TaskListItemDescriptor(token, priority)); } } diff --git a/src/Workspaces/Core/Portable/Workspace/Host/SolutionServices.cs b/src/Workspaces/Core/Portable/Workspace/Host/SolutionServices.cs index cc1c92c0c383c..a49f51dc7fdc1 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/SolutionServices.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/SolutionServices.cs @@ -53,5 +53,8 @@ public LanguageServices GetLanguageServices(string languageName) public TLanguageService GetRequiredLanguageService(string language) where TLanguageService : ILanguageService => this.GetLanguageServices(language).GetRequiredService(); + + internal IEnumerable FindLanguageServices(HostWorkspaceServices.MetadataFilter filter) + => _services.FindLanguageServices(filter); } } diff --git a/src/Workspaces/Core/Portable/Workspace/IWorkspaceConfigurationService.cs b/src/Workspaces/Core/Portable/Workspace/IWorkspaceConfigurationService.cs index 532d6e4451476..fc7a08029c276 100644 --- a/src/Workspaces/Core/Portable/Workspace/IWorkspaceConfigurationService.cs +++ b/src/Workspaces/Core/Portable/Workspace/IWorkspaceConfigurationService.cs @@ -2,7 +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. +using System; +using System.Composition; using System.Runtime.Serialization; +using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Storage; namespace Microsoft.CodeAnalysis.Host @@ -12,6 +15,18 @@ internal interface IWorkspaceConfigurationService : IWorkspaceService WorkspaceConfigurationOptions Options { get; } } + [ExportWorkspaceService(typeof(IWorkspaceConfigurationService)), Shared] + internal sealed class DefaultWorkspaceConfigurationService : IWorkspaceConfigurationService + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public DefaultWorkspaceConfigurationService() + { + } + + public WorkspaceConfigurationOptions Options => WorkspaceConfigurationOptions.Default; + } + /// /// Options that affect behavior of workspace core APIs (, , , , etc.) to which it would be impractical to flow these options @@ -25,9 +40,9 @@ internal interface IWorkspaceConfigurationService : IWorkspaceService internal readonly record struct WorkspaceConfigurationOptions( [property: DataMember(Order = 0)] StorageDatabase CacheStorage = StorageDatabase.SQLite, [property: DataMember(Order = 1)] bool EnableOpeningSourceGeneratedFiles = false, - [property: DataMember(Order = 2)] bool DisableCloneWhenProducingSkeletonReferences = false, - [property: DataMember(Order = 3)] bool DisableReferenceManagerRecoverableMetadata = false, - [property: DataMember(Order = 4)] bool DisableBackgroundCompilation = false) + [property: DataMember(Order = 2)] bool DisableReferenceManagerRecoverableMetadata = false, + [property: DataMember(Order = 3)] bool DisableBackgroundCompilation = false, + [property: DataMember(Order = 4)] bool DisableSharedSyntaxTrees = false) { public WorkspaceConfigurationOptions() : this(CacheStorage: StorageDatabase.SQLite) @@ -43,8 +58,8 @@ public WorkspaceConfigurationOptions() public static readonly WorkspaceConfigurationOptions RemoteDefault = new( CacheStorage: StorageDatabase.None, EnableOpeningSourceGeneratedFiles: false, - DisableCloneWhenProducingSkeletonReferences: false, DisableReferenceManagerRecoverableMetadata: false, - DisableBackgroundCompilation: false); + DisableBackgroundCompilation: false, + DisableSharedSyntaxTrees: false); } } diff --git a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/IProjectSystemDiagnosticSource.cs b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/IProjectSystemDiagnosticSource.cs index 5eba4548b6aad..45beadea5fcf1 100644 --- a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/IProjectSystemDiagnosticSource.cs +++ b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/IProjectSystemDiagnosticSource.cs @@ -14,6 +14,7 @@ internal interface IProjectSystemDiagnosticSource void ClearAllDiagnosticsForProject(ProjectId projectId); void ClearAnalyzerReferenceDiagnostics(AnalyzerFileReference fileReference, string language, ProjectId projectId); void ClearDiagnosticsForProject(ProjectId projectId, object key); + DiagnosticData CreateAnalyzerLoadFailureDiagnostic(AnalyzerLoadFailureEventArgs e, string fullPath, ProjectId projectId, string language); void UpdateDiagnosticsForProject(ProjectId projectId, object key, IEnumerable items); } } diff --git a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioProject.BatchingDocumentCollection.cs b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProject.BatchingDocumentCollection.cs similarity index 92% rename from src/VisualStudio/Core/Def/ProjectSystem/VisualStudioProject.BatchingDocumentCollection.cs rename to src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProject.BatchingDocumentCollection.cs index bc883d15d3890..c540972705c76 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioProject.BatchingDocumentCollection.cs +++ b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProject.BatchingDocumentCollection.cs @@ -17,19 +17,19 @@ using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; -namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem +namespace Microsoft.CodeAnalysis.Workspaces.ProjectSystem { - internal sealed partial class VisualStudioProject + internal sealed partial class ProjectSystemProject { /// /// Helper class to manage collections of source-file like things; this exists just to avoid duplicating all the logic for regular source files /// and additional files. /// - /// This class should be free-threaded, and any synchronization is done via . + /// This class should be free-threaded, and any synchronization is done via . /// This class is otherwise free to operate on private members of if needed. private sealed class BatchingDocumentCollection { - private readonly VisualStudioProject _project; + private readonly ProjectSystemProject _project; /// /// The map of file paths to the underlying . This document may exist in or has been @@ -69,7 +69,7 @@ private sealed class BatchingDocumentCollection private readonly Func _documentTextLoaderChangedAction; private readonly WorkspaceChangeKind _documentChangedWorkspaceKind; - public BatchingDocumentCollection(VisualStudioProject project, + public BatchingDocumentCollection(ProjectSystemProject project, Func documentAlreadyInWorkspace, Action documentAddAction, Action documentRemoveAction, @@ -92,7 +92,7 @@ public DocumentId AddFile(string fullPath, SourceCodeKind sourceCodeKind, Immuta } var documentId = DocumentId.CreateNewId(_project.Id, fullPath); - var textLoader = new WorkspaceFileTextLoader(_project._workspace.Services.SolutionServices, fullPath, defaultEncoding: null); + var textLoader = new WorkspaceFileTextLoader(_project._projectSystemProjectFactory.Workspace.Services.SolutionServices, fullPath, defaultEncoding: null); var documentInfo = DocumentInfo.Create( documentId, name: FileNameUtilities.GetFileName(fullPath), @@ -120,8 +120,8 @@ public DocumentId AddFile(string fullPath, SourceCodeKind sourceCodeKind, Immuta } else { - _project._workspace.ApplyChangeToWorkspace(w => _documentAddAction(w, documentInfo)); - _project._workspace.QueueCheckForFilesBeingOpen(ImmutableArray.Create(fullPath)); + _project._projectSystemProjectFactory.ApplyChangeToWorkspace(w => _documentAddAction(w, documentInfo)); + _project._projectSystemProjectFactory.RaiseOnDocumentsAdded(ImmutableArray.Create(fullPath)); } } @@ -178,9 +178,9 @@ public DocumentId AddTextContainer( } else { - _project._workspace.ApplyChangeToWorkspace(w => + _project._projectSystemProjectFactory.ApplyChangeToWorkspace(w => { - _project._workspace.AddDocumentToDocumentsNotFromFiles_NoLock(documentInfo.Id); + _project._projectSystemProjectFactory.AddDocumentToDocumentsNotFromFiles_NoLock(documentInfo.Id); _documentAddAction(w, documentInfo); w.OnDocumentOpened(documentInfo.Id, textContainer); }); @@ -226,7 +226,7 @@ public void AddDynamicFile_NoLock(IDynamicFileInfoProvider fileInfoProvider, Dyn else { // right now, assumption is dynamically generated file can never be opened in editor - _project._workspace.ApplyChangeToWorkspace(w => _documentAddAction(w, documentInfo)); + _project._projectSystemProjectFactory.ApplyChangeToWorkspace(w => _documentAddAction(w, documentInfo)); } } @@ -283,7 +283,7 @@ private void RemoveFileInternal(DocumentId documentId, string fullPath) // 1. This file is actually been pushed to the workspace, and we need to remove it (either // as a part of the active batch or immediately) // 2. It hasn't been pushed yet, but is contained in _documentsAddedInBatch - if (_documentAlreadyInWorkspace(_project._workspace.CurrentSolution, documentId)) + if (_documentAlreadyInWorkspace(_project._projectSystemProjectFactory.Workspace.CurrentSolution, documentId)) { if (_project._activeBatchScopes > 0) { @@ -291,7 +291,7 @@ private void RemoveFileInternal(DocumentId documentId, string fullPath) } else { - _project._workspace.ApplyChangeToWorkspace(w => _documentRemoveAction(w, documentId)); + _project._projectSystemProjectFactory.ApplyChangeToWorkspace(w => _documentRemoveAction(w, documentId)); } } else @@ -335,7 +335,7 @@ public void RemoveTextContainer(SourceTextContainer textContainer) // 1. This file is actually been pushed to the workspace, and we need to remove it (either // as a part of the active batch or immediately) // 2. It hasn't been pushed yet, but is contained in _documentsAddedInBatch - if (_project._workspace.CurrentSolution.GetDocument(documentId) != null) + if (_project._projectSystemProjectFactory.Workspace.CurrentSolution.GetDocument(documentId) != null) { if (_project._activeBatchScopes > 0) { @@ -343,7 +343,7 @@ public void RemoveTextContainer(SourceTextContainer textContainer) } else { - _project._workspace.ApplyChangeToWorkspace(w => + _project._projectSystemProjectFactory.ApplyChangeToWorkspace(w => { // Just pass null for the filePath, since this document is immediately being removed // anyways -- whatever we set won't really be read since the next change will @@ -351,7 +351,7 @@ public void RemoveTextContainer(SourceTextContainer textContainer) // TODO: Can't we just remove the document without closing it? w.OnDocumentClosed(documentId, new SourceTextLoader(textContainer, filePath: null)); _documentRemoveAction(w, documentId); - _project._workspace.RemoveDocumentToDocumentsNotFromFiles_NoLock(documentId); + _project._projectSystemProjectFactory.RemoveDocumentToDocumentsNotFromFiles_NoLock(documentId); }); } } @@ -405,7 +405,7 @@ public async ValueTask ProcessRegularFileChangesAsync(ImmutableSegmentedList d.Id == documentId)) { - documentsToChange.Add((documentId, new WorkspaceFileTextLoader(_project._workspace.Services.SolutionServices, filePath, defaultEncoding: null))); + documentsToChange.Add((documentId, new WorkspaceFileTextLoader(_project._projectSystemProjectFactory.Workspace.Services.SolutionServices, filePath, defaultEncoding: null))); } } } @@ -416,11 +416,11 @@ public async ValueTask ProcessRegularFileChangesAsync(ImmutableSegmentedList + await _project._projectSystemProjectFactory.ApplyBatchChangeToWorkspaceAsync(solutionChanges => { foreach (var (documentId, textLoader) in documentsToChange) { - if (!_project._workspace.IsDocumentOpen(documentId)) + if (!_project._projectSystemProjectFactory.Workspace.IsDocumentOpen(documentId)) { solutionChanges.UpdateSolutionForDocumentAction( _documentTextLoaderChangedAction(solutionChanges.Solution, documentId, textLoader), @@ -463,7 +463,7 @@ public void ProcessDynamicFileChange(string projectSystemFilePath, string worksp Contract.ThrowIfFalse(_documentIdToDynamicFileInfoProvider.TryGetValue(documentId, out var fileInfoProvider)); - _project._workspace.ApplyChangeToWorkspace(w => + _project._projectSystemProjectFactory.ApplyChangeToWorkspace(w => { if (w.IsDocumentOpen(documentId)) { @@ -521,7 +521,7 @@ public void ReorderFiles(ImmutableArray filePaths) } else { - _project._workspace.ApplyChangeToWorkspace(_project.Id, solution => solution.WithProjectDocumentsOrder(_project.Id, documentIds.ToImmutable())); + _project._projectSystemProjectFactory.ApplyChangeToWorkspace(_project.Id, solution => solution.WithProjectDocumentsOrder(_project.Id, documentIds.ToImmutable())); } } } diff --git a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioProject.cs b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProject.cs similarity index 89% rename from src/VisualStudio/Core/Def/ProjectSystem/VisualStudioProject.cs rename to src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProject.cs index 46a785aee26e7..12c2767ad25be 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioProject.cs +++ b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProject.cs @@ -21,26 +21,17 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Telemetry; using Microsoft.CodeAnalysis.Text; -using Microsoft.CodeAnalysis.Workspaces.ProjectSystem; -using Microsoft.VisualStudio.LanguageServices.Implementation.Diagnostics; -using Microsoft.VisualStudio.LanguageServices.Implementation.TaskList; using Roslyn.Utilities; -namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem +namespace Microsoft.CodeAnalysis.Workspaces.ProjectSystem { - internal sealed partial class VisualStudioProject + internal sealed partial class ProjectSystemProject { private static readonly char[] s_directorySeparator = { Path.DirectorySeparatorChar }; private static readonly ImmutableArray s_defaultMetadataReferenceProperties = ImmutableArray.Create(default(MetadataReferenceProperties)); - private readonly VisualStudioWorkspaceImpl _workspace; - private readonly IProjectSystemDiagnosticSource _projectSystemDiagnosticSource; - private readonly IHostDiagnosticAnalyzerProvider _hostAnalyzerProvider; - - /// - /// Provides dynamic source files for files added through . - /// - private readonly ImmutableArray> _dynamicFileInfoProviders; + private readonly ProjectSystemProjectFactory _projectSystemProjectFactory; + private readonly ProjectSystemHostInfo _hostInfo; /// /// A semaphore taken for all mutation of any mutable field in this type. @@ -59,14 +50,14 @@ internal sealed partial class VisualStudioProject private readonly List _projectReferencesAddedInBatch = new(); private readonly List _projectReferencesRemovedInBatch = new(); - private readonly Dictionary _analyzerPathsToAnalyzers = new(); - private readonly List _analyzersAddedInBatch = new(); + private readonly Dictionary _analyzerPathsToAnalyzers = new(); + private readonly List _analyzersAddedInBatch = new(); /// - /// The list of that will be removed in this batch. They have not yet + /// The list of that will be removed in this batch. They have not yet /// been disposed, and will be disposed once the batch is applied. /// - private readonly List _analyzersRemovedInBatch = new(); + private readonly List _analyzersRemovedInBatch = new(); private readonly List> _projectPropertyModificationsInBatch = new(); @@ -148,11 +139,9 @@ internal sealed partial class VisualStudioProject public ProjectId Id { get; } public string Language { get; } - internal VisualStudioProject( - VisualStudioWorkspaceImpl workspace, - ImmutableArray> dynamicFileInfoProviders, - IProjectSystemDiagnosticSource projectSystemDiagnosticSource, - IHostDiagnosticAnalyzerProvider hostAnalyzerProvider, + internal ProjectSystemProject( + ProjectSystemProjectFactory projectSystemProjectFactory, + ProjectSystemHostInfo hostInfo, ProjectId id, string displayName, string language, @@ -161,10 +150,8 @@ internal VisualStudioProject( string? filePath, ParseOptions? parseOptions) { - _workspace = workspace; - _dynamicFileInfoProviders = dynamicFileInfoProviders; - _projectSystemDiagnosticSource = projectSystemDiagnosticSource; - _hostAnalyzerProvider = hostAnalyzerProvider; + _projectSystemProjectFactory = projectSystemProjectFactory; + _hostInfo = hostInfo; Id = id; Language = language; @@ -196,7 +183,7 @@ internal VisualStudioProject( TimeSpan.FromMilliseconds(200), // 200 chosen with absolutely no evidence whatsoever ProcessFileChangesAsync, StringComparer.Ordinal, - workspace.Services.GetRequiredService().GetListener(), + _projectSystemProjectFactory.WorkspaceListener, _asynchronousFileChangeProcessingCancellationTokenSource.Token); _assemblyName = assemblyName; @@ -210,12 +197,12 @@ internal VisualStudioProject( { // Since we have a project directory, we'll just watch all the files under that path; that'll avoid extra overhead of // having to add explicit file watches everywhere. - var projectDirectoryToWatch = new WatchedDirectory(Path.GetDirectoryName(filePath), fileExtensionToWatch); - _documentFileChangeContext = _workspace.FileChangeWatcher.CreateContext(projectDirectoryToWatch); + var projectDirectoryToWatch = new WatchedDirectory(Path.GetDirectoryName(filePath)!, fileExtensionToWatch); + _documentFileChangeContext = _projectSystemProjectFactory.FileChangeWatcher.CreateContext(projectDirectoryToWatch); } else { - _documentFileChangeContext = workspace.FileChangeWatcher.CreateContext(); + _documentFileChangeContext = _projectSystemProjectFactory.FileChangeWatcher.CreateContext(); } _documentFileChangeContext.FileChanged += DocumentFileChangeContext_FileChanged; @@ -246,11 +233,11 @@ private void ChangeProjectProperty(ref T field, T newValue, Action(); + var telemetryService = _projectSystemProjectFactory.Workspace.Services.GetService(); if (telemetryService?.HasActiveSession == true) { - var workspaceStatusService = _workspace.Services.GetService(); + var workspaceStatusService = _projectSystemProjectFactory.Workspace.Services.GetService(); // We only log telemetry during solution open @@ -264,7 +251,7 @@ private void ChangeProjectProperty(ref T field, T newValue, Action(ref T field, T newValue, Action + _projectSystemProjectFactory.ApplyBatchChangeToWorkspace(solutionChanges => { updateSolution(solutionChanges, oldValue); }); @@ -324,12 +311,12 @@ private void ChangeProjectOutputPath(ref string? field, string? newValue, Func internal string? MaxLangVersion { - set => _workspace.SetMaxLanguageVersion(Id, value); + set => _projectSystemProjectFactory.SetMaxLanguageVersion(Id, value); } internal string DependencyNodeTargetIdentifier { - set => _workspace.SetDependencyNodeTargetIdentifier(Id, value); + set => _projectSystemProjectFactory.SetDependencyNodeTargetIdentifier(Id, value); } - private bool HasBeenRemoved => !_workspace.CurrentSolution.ContainsProject(Id); + private bool HasBeenRemoved => !_projectSystemProjectFactory.Workspace.CurrentSolution.ContainsProject(Id); #region Batching @@ -481,14 +468,14 @@ public BatchScope CreateBatchScope() public sealed class BatchScope : IDisposable, IAsyncDisposable { - private readonly VisualStudioProject _project; + private readonly ProjectSystemProject _project; /// /// Flag to control if this has already been disposed. Not a boolean only so it can be used with Interlocked.CompareExchange. /// private volatile int _disposed = 0; - internal BatchScope(VisualStudioProject visualStudioProject) + internal BatchScope(ProjectSystemProject visualStudioProject) => _project = visualStudioProject; public void Dispose() @@ -530,7 +517,7 @@ private async Task OnBatchScopeDisposedMaybeAsync(bool useAsync) var additionalDocumentsToOpen = new List<(DocumentId documentId, SourceTextContainer textContainer)>(); var analyzerConfigDocumentsToOpen = new List<(DocumentId documentId, SourceTextContainer textContainer)>(); - await _workspace.ApplyBatchChangeToWorkspaceMaybeAsync(useAsync, solutionChanges => + await _projectSystemProjectFactory.ApplyBatchChangeToWorkspaceMaybeAsync(useAsync, solutionChanges => { _sourceFiles.UpdateSolutionForBatch( solutionChanges, @@ -572,7 +559,7 @@ await _workspace.ApplyBatchChangeToWorkspaceMaybeAsync(useAsync, solutionChanges // a different output path (say bin vs. obj vs. ref). foreach (var (path, properties) in _metadataReferencesRemovedInBatch) { - var projectReference = _workspace.TryRemoveConvertedProjectReference_NoLock(Id, path, properties); + var projectReference = _projectSystemProjectFactory.TryRemoveConvertedProjectReference_NoLock(Id, path, properties); if (projectReference != null) { @@ -583,10 +570,10 @@ await _workspace.ApplyBatchChangeToWorkspaceMaybeAsync(useAsync, solutionChanges else { // TODO: find a cleaner way to fetch this - var metadataReference = _workspace.CurrentSolution.GetRequiredProject(Id).MetadataReferences.Cast() + var metadataReference = _projectSystemProjectFactory.Workspace.CurrentSolution.GetRequiredProject(Id).MetadataReferences.Cast() .Single(m => m.FilePath == path && m.Properties == properties); - _workspace.FileWatchedReferenceFactory.StopWatchingReference(metadataReference); + _projectSystemProjectFactory.FileWatchedReferenceFactory.StopWatchingReference(metadataReference); solutionChanges.UpdateSolutionForProjectAction( Id, @@ -604,7 +591,7 @@ await _workspace.ApplyBatchChangeToWorkspaceMaybeAsync(useAsync, solutionChanges foreach (var (path, properties) in _metadataReferencesAddedInBatch) { - var projectReference = _workspace.TryCreateConvertedProjectReference_NoLock(Id, path, properties); + var projectReference = _projectSystemProjectFactory.TryCreateConvertedProjectReference_NoLock(Id, path, properties); if (projectReference != null) { @@ -612,7 +599,7 @@ await _workspace.ApplyBatchChangeToWorkspaceMaybeAsync(useAsync, solutionChanges } else { - var metadataReference = _workspace.FileWatchedReferenceFactory.CreateReferenceAndStartWatchingFile(path, properties); + var metadataReference = _projectSystemProjectFactory.FileWatchedReferenceFactory.CreateReferenceAndStartWatchingFile(path, properties); metadataReferencesCreated.Add(metadataReference); } } @@ -670,21 +657,21 @@ await _workspace.ApplyBatchChangeToWorkspaceMaybeAsync(useAsync, solutionChanges foreach (var (documentId, textContainer) in documentsToOpen) { - await _workspace.ApplyChangeToWorkspaceMaybeAsync(useAsync, w => w.OnDocumentOpened(documentId, textContainer)).ConfigureAwait(false); + await _projectSystemProjectFactory.ApplyChangeToWorkspaceMaybeAsync(useAsync, w => w.OnDocumentOpened(documentId, textContainer)).ConfigureAwait(false); } foreach (var (documentId, textContainer) in additionalDocumentsToOpen) { - await _workspace.ApplyChangeToWorkspaceMaybeAsync(useAsync, w => w.OnAdditionalDocumentOpened(documentId, textContainer)).ConfigureAwait(false); + await _projectSystemProjectFactory.ApplyChangeToWorkspaceMaybeAsync(useAsync, w => w.OnAdditionalDocumentOpened(documentId, textContainer)).ConfigureAwait(false); } foreach (var (documentId, textContainer) in analyzerConfigDocumentsToOpen) { - await _workspace.ApplyChangeToWorkspaceMaybeAsync(useAsync, w => w.OnAnalyzerConfigDocumentOpened(documentId, textContainer)).ConfigureAwait(false); + await _projectSystemProjectFactory.ApplyChangeToWorkspaceMaybeAsync(useAsync, w => w.OnAnalyzerConfigDocumentOpened(documentId, textContainer)).ConfigureAwait(false); } - // Check for those files being opened to start wire-up if necessary - _workspace.QueueCheckForFilesBeingOpen(documentFileNamesAdded.ToImmutable()); + // Give the host the opportunity to check if those files are open + _projectSystemProjectFactory.RaiseOnDocumentsAdded(documentFileNamesAdded.ToImmutable()); } } @@ -770,7 +757,7 @@ public void AddDynamicSourceFile(string dynamicFilePath, ImmutableArray } else { - foreach (var provider in _dynamicFileInfoProviders) + foreach (var provider in _hostInfo.DynamicFileInfoProviders) { // skip unrelated providers if (!provider.Metadata.Extensions.Any(e => string.Equals(e, extension, StringComparison.OrdinalIgnoreCase))) @@ -864,7 +851,7 @@ public void RemoveDynamicSourceFile(string dynamicFilePath) projectId: Id, projectFilePath: _filePath, filePath: dynamicFilePath, CancellationToken.None).Wait(CancellationToken.None); } - private void OnDynamicFileInfoUpdated(object sender, string dynamicFilePath) + private void OnDynamicFileInfoUpdated(object? sender, string dynamicFilePath) { string? fileInfoPath; @@ -918,9 +905,9 @@ public void AddAnalyzerReference(string fullPath) else { // Nope, we actually need to make a new one. - var visualStudioAnalyzer = new VisualStudioAnalyzer( + var visualStudioAnalyzer = new ProjectAnalyzerReference( mappedFullPath, - _projectSystemDiagnosticSource, + _hostInfo.DiagnosticSource, Id, Language); @@ -932,7 +919,7 @@ public void AddAnalyzerReference(string fullPath) } else { - _workspace.ApplyChangeToWorkspace(w => w.OnAnalyzerReferenceAdded(Id, visualStudioAnalyzer.GetReference())); + _projectSystemProjectFactory.ApplyChangeToWorkspace(w => w.OnAnalyzerReferenceAdded(Id, visualStudioAnalyzer.GetReference())); } } } @@ -981,7 +968,7 @@ public void RemoveAnalyzerReference(string fullPath) } else { - _workspace.ApplyChangeToWorkspace(w => w.OnAnalyzerReferenceRemoved(Id, visualStudioAnalyzer.GetReference())); + _projectSystemProjectFactory.ApplyChangeToWorkspace(w => w.OnAnalyzerReferenceRemoved(Id, visualStudioAnalyzer.GetReference())); visualStudioAnalyzer.Dispose(); } @@ -1000,7 +987,7 @@ private OneOrMany GetMappedAnalyzerPaths(string fullPath) if (fullPath.LastIndexOf(s_razorSourceGeneratorSdkDirectory, StringComparison.OrdinalIgnoreCase) + s_razorSourceGeneratorSdkDirectory.Length - 1 == fullPath.LastIndexOf(Path.DirectorySeparatorChar)) { - var vsixRazorAnalyzers = _hostAnalyzerProvider.GetAnalyzerReferencesInExtensions().SelectAsArray( + var vsixRazorAnalyzers = _hostInfo.HostDiagnosticAnalyzerProvider.GetAnalyzerReferencesInExtensions().SelectAsArray( predicate: item => item.extensionId == RazorVsixExtensionId, selector: item => item.reference.FullPath); @@ -1020,7 +1007,7 @@ private OneOrMany GetMappedAnalyzerPaths(string fullPath) #endregion - private void DocumentFileChangeContext_FileChanged(object sender, string fullFilePath) + private void DocumentFileChangeContext_FileChanged(object? sender, string fullFilePath) { _fileChangesToProcess.AddWork(fullFilePath); } @@ -1059,9 +1046,9 @@ public void AddMetadataReference(string fullPath, MetadataReferenceProperties pr } else { - _workspace.ApplyChangeToWorkspace(w => + _projectSystemProjectFactory.ApplyChangeToWorkspace(w => { - var projectReference = _workspace.TryCreateConvertedProjectReference_NoLock(Id, fullPath, properties); + var projectReference = _projectSystemProjectFactory.TryCreateConvertedProjectReference_NoLock(Id, fullPath, properties); if (projectReference != null) { @@ -1069,7 +1056,7 @@ public void AddMetadataReference(string fullPath, MetadataReferenceProperties pr } else { - var metadataReference = _workspace.FileWatchedReferenceFactory.CreateReferenceAndStartWatchingFile(fullPath, properties); + var metadataReference = _projectSystemProjectFactory.FileWatchedReferenceFactory.CreateReferenceAndStartWatchingFile(fullPath, properties); w.OnMetadataReferenceAdded(Id, metadataReference); } }); @@ -1129,9 +1116,9 @@ public void RemoveMetadataReference(string fullPath, MetadataReferenceProperties } else { - _workspace.ApplyChangeToWorkspace(w => + _projectSystemProjectFactory.ApplyChangeToWorkspace(w => { - var projectReference = _workspace.TryRemoveConvertedProjectReference_NoLock(Id, fullPath, properties); + var projectReference = _projectSystemProjectFactory.TryRemoveConvertedProjectReference_NoLock(Id, fullPath, properties); // If this was converted to a project reference, we have now recorded the removal -- let's remove it here too if (projectReference != null) @@ -1144,7 +1131,7 @@ public void RemoveMetadataReference(string fullPath, MetadataReferenceProperties var metadataReference = w.CurrentSolution.GetRequiredProject(Id).MetadataReferences.Cast() .Single(m => m.FilePath == fullPath && m.Properties == properties); - _workspace.FileWatchedReferenceFactory.StopWatchingReference(metadataReference); + _projectSystemProjectFactory.FileWatchedReferenceFactory.StopWatchingReference(metadataReference); w.OnMetadataReferenceRemoved(Id, metadataReference); } }); @@ -1179,7 +1166,7 @@ public void AddProjectReference(ProjectReference projectReference) } else { - _workspace.ApplyChangeToWorkspace(w => w.OnProjectReferenceAdded(Id, projectReference)); + _projectSystemProjectFactory.ApplyChangeToWorkspace(w => w.OnProjectReferenceAdded(Id, projectReference)); } } } @@ -1211,7 +1198,7 @@ private bool ContainsProjectReference_NoLock(ProjectReference projectReference) return true; } - return _workspace.CurrentSolution.GetRequiredProject(Id).AllProjectReferences.Contains(projectReference); + return _projectSystemProjectFactory.Workspace.CurrentSolution.GetRequiredProject(Id).AllProjectReferences.Contains(projectReference); } public IReadOnlyList GetProjectReferences() @@ -1219,7 +1206,7 @@ public IReadOnlyList GetProjectReferences() using (_gate.DisposableWait()) { // If we're not batching, then this is cheap: just fetch from the workspace and we're done - var projectReferencesInWorkspace = _workspace.CurrentSolution.GetRequiredProject(Id).AllProjectReferences; + var projectReferencesInWorkspace = _projectSystemProjectFactory.Workspace.CurrentSolution.GetRequiredProject(Id).AllProjectReferences; if (_activeBatchScopes == 0) { @@ -1258,7 +1245,7 @@ public void RemoveProjectReference(ProjectReference projectReference) } else { - _workspace.ApplyChangeToWorkspace(w => w.OnProjectReferenceRemoved(Id, projectReference)); + _projectSystemProjectFactory.ApplyChangeToWorkspace(w => w.OnProjectReferenceRemoved(Id, projectReference)); } } } @@ -1269,7 +1256,7 @@ public void RemoveFromWorkspace() { using (_gate.DisposableWait()) { - if (!_workspace.CurrentSolution.ContainsProject(Id)) + if (!_projectSystemProjectFactory.Workspace.CurrentSolution.ContainsProject(Id)) { throw new InvalidOperationException("The project has already been removed."); } @@ -1289,23 +1276,23 @@ public void RemoveFromWorkspace() IReadOnlyList? remainingMetadataReferences = null; - _workspace.ApplyChangeToWorkspace(w => + _projectSystemProjectFactory.ApplyChangeToWorkspace(w => { // Acquire the remaining metadata references inside the workspace lock. This is critical // as another project being removed at the same time could result in project to project // references being converted to metadata references (or vice versa) and we might either // miss stopping a file watcher or might end up double-stopping a file watcher. remainingMetadataReferences = w.CurrentSolution.GetRequiredProject(Id).MetadataReferences; - _workspace.RemoveProjectFromTrackingMaps_NoLock(Id); + _projectSystemProjectFactory.RemoveProjectFromTrackingMaps_NoLock(Id); // If this is our last project, clear the entire solution. if (w.CurrentSolution.ProjectIds.Count == 1) { - _workspace.RemoveSolution_NoLock(); + _projectSystemProjectFactory.RemoveSolution_NoLock(); } else { - _workspace.OnProjectRemoved(Id); + _projectSystemProjectFactory.Workspace.OnProjectRemoved(Id); } }); @@ -1313,7 +1300,7 @@ public void RemoveFromWorkspace() foreach (PortableExecutableReference reference in remainingMetadataReferences) { - _workspace.FileWatchedReferenceFactory.StopWatchingReference(reference); + _projectSystemProjectFactory.FileWatchedReferenceFactory.StopWatchingReference(reference); } // Dispose of any analyzers that might still be around to remove their load diagnostics diff --git a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectCreationInfo.cs b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectCreationInfo.cs new file mode 100644 index 0000000000000..51f48ae74ae69 --- /dev/null +++ b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectCreationInfo.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; +using Microsoft.CodeAnalysis; + +namespace Microsoft.CodeAnalysis.Workspaces.ProjectSystem +{ + internal class ProjectSystemProjectCreationInfo + { + public string? AssemblyName { get; set; } + public CompilationOptions? CompilationOptions { get; set; } + public string? FilePath { get; set; } + public ParseOptions? ParseOptions { get; set; } + + public Guid TelemetryId { get; set; } + } +} diff --git a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectFactory.cs b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectFactory.cs new file mode 100644 index 0000000000000..efc95bd15920d --- /dev/null +++ b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectFactory.cs @@ -0,0 +1,657 @@ +// 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.IO; +using System.Linq; +using System.Reflection.Metadata.Ecma335; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.ProjectSystem; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Workspaces.ProjectSystem +{ + internal sealed class ProjectSystemProjectFactory + { + /// + /// The main gate to synchronize updates to this solution. + /// + /// + /// See the Readme.md in this directory for further comments about threading in this area. + /// + // TODO: we should be able to get rid of this gate in favor of just calling the various workspace methods that acquire the Workspace's + // serialization lock and then allow us to update our own state under that lock. + private readonly SemaphoreSlim _gate = new SemaphoreSlim(initialCount: 1); + + public Workspace Workspace { get; } + public IAsynchronousOperationListener WorkspaceListener { get; } + public IFileChangeWatcher FileChangeWatcher { get; } + public FileWatchedPortableExecutableReferenceFactory FileWatchedReferenceFactory { get; } + + private readonly Action> _onDocumentsAdded; + private readonly Action _onProjectRemoved; + + /// + /// A set of documents that were added by , and aren't otherwise + /// tracked for opening/closing. + /// + public ImmutableHashSet DocumentsNotFromFiles { get; private set; } = ImmutableHashSet.Empty; + + /// Should be updated with . + private ImmutableDictionary _projectToMaxSupportedLangVersionMap = ImmutableDictionary.Empty; + + /// Should be updated with . + private ImmutableDictionary _projectToDependencyNodeTargetIdentifier = ImmutableDictionary.Empty; + + /// + /// Set by the host if the solution is currently closing; this can be used to optimize some things there. + /// + public bool SolutionClosing { get; set; } + + /// + /// The current path to the solution. Currently this is only used to update the solution path when the first project is added -- we don't have a concept + /// of the solution path changing in the middle while a bunch of projects are loaded. + /// + public string? SolutionPath { get; set; } + public Guid SolutionTelemetryId { get; set; } + + public ProjectSystemProjectFactory(Workspace workspace, IFileChangeWatcher fileChangeWatcher, Action> onDocumentsAdded, Action onProjectRemoved) + { + Workspace = workspace; + WorkspaceListener = workspace.Services.GetRequiredService().GetListener(); + + FileChangeWatcher = fileChangeWatcher; + FileWatchedReferenceFactory = new FileWatchedPortableExecutableReferenceFactory(workspace.Services.SolutionServices, fileChangeWatcher); + FileWatchedReferenceFactory.ReferenceChanged += this.StartRefreshingMetadataReferencesForFile; + + _onDocumentsAdded = onDocumentsAdded; + _onProjectRemoved = onProjectRemoved; + } + + public async Task CreateAndAddToWorkspaceAsync(string projectSystemName, string language, ProjectSystemProjectCreationInfo creationInfo, ProjectSystemHostInfo hostInfo) + { + var id = ProjectId.CreateNewId(projectSystemName); + var assemblyName = creationInfo.AssemblyName ?? projectSystemName; + + // We will use the project system name as the default display name of the project + var project = new ProjectSystemProject( + this, + hostInfo, + id, + displayName: projectSystemName, + language, + assemblyName: assemblyName, + compilationOptions: creationInfo.CompilationOptions, + filePath: creationInfo.FilePath, + parseOptions: creationInfo.ParseOptions); + + var versionStamp = creationInfo.FilePath != null ? VersionStamp.Create(File.GetLastWriteTimeUtc(creationInfo.FilePath)) + : VersionStamp.Create(); + + await ApplyChangeToWorkspaceAsync(w => + { + var projectInfo = ProjectInfo.Create( + new ProjectInfo.ProjectAttributes( + id, + versionStamp, + name: projectSystemName, + assemblyName: assemblyName, + language: language, + checksumAlgorithm: SourceHashAlgorithms.Default, // will be updated when command line is set + compilationOutputFilePaths: default, // will be updated when command line is set + filePath: creationInfo.FilePath, + telemetryId: creationInfo.TelemetryId), + compilationOptions: creationInfo.CompilationOptions, + parseOptions: creationInfo.ParseOptions); + + // If we don't have any projects and this is our first project being added, then we'll create a new SolutionId + // and count this as the solution being added so that event is raised. + if (w.CurrentSolution.ProjectIds.Count == 0) + { + w.OnSolutionAdded( + SolutionInfo.Create( + SolutionId.CreateNewId(SolutionPath), + VersionStamp.Create(), + SolutionPath, + projects: new[] { projectInfo }, + analyzerReferences: w.CurrentSolution.AnalyzerReferences) + .WithTelemetryId(SolutionTelemetryId)); + } + else + { + w.OnProjectAdded(projectInfo); + } + }).ConfigureAwait(false); + + return project; + } + + public string? TryGetDependencyNodeTargetIdentifier(ProjectId projectId) + { + // This doesn't take a lock since _projectToDependencyNodeTargetIdentifier is immutable + _projectToDependencyNodeTargetIdentifier.TryGetValue(projectId, out var identifier); + return identifier; + } + + public string? TryGetMaxSupportedLanguageVersion(ProjectId projectId) + { + // This doesn't take a lock since _projectToMaxSupportedLangVersionMap is immutable + _projectToMaxSupportedLangVersionMap.TryGetValue(projectId, out var identifier); + return identifier; + } + + internal void AddDocumentToDocumentsNotFromFiles_NoLock(DocumentId documentId) + { + Contract.ThrowIfFalse(_gate.CurrentCount == 0); + + DocumentsNotFromFiles = DocumentsNotFromFiles.Add(documentId); + } + + internal void RemoveDocumentToDocumentsNotFromFiles_NoLock(DocumentId documentId) + { + Contract.ThrowIfFalse(_gate.CurrentCount == 0); + DocumentsNotFromFiles = DocumentsNotFromFiles.Remove(documentId); + } + /// + /// Applies a single operation to the workspace. should be a call to one of the protected Workspace.On* methods. + /// + public void ApplyChangeToWorkspace(Action action) + { + using (_gate.DisposableWait()) + { + action(Workspace); + } + } + + /// + /// Applies a single operation to the workspace. should be a call to one of the protected Workspace.On* methods. + /// + public async ValueTask ApplyChangeToWorkspaceAsync(Action action) + { + using (await _gate.DisposableWaitAsync().ConfigureAwait(false)) + { + action(Workspace); + } + } + + /// + /// Applies a single operation to the workspace. should be a call to one of the protected Workspace.On* methods. + /// + public async ValueTask ApplyChangeToWorkspaceMaybeAsync(bool useAsync, Action action) + { + using (useAsync ? await _gate.DisposableWaitAsync().ConfigureAwait(false) : _gate.DisposableWait()) + { + action(Workspace); + } + } + + /// + /// Applies a solution transformation to the workspace and triggers workspace changed event for specified . + /// The transformation shall only update the project of the solution with the specified . + /// + public void ApplyChangeToWorkspace(ProjectId projectId, Func solutionTransformation) + { + using (_gate.DisposableWait()) + { + Workspace.SetCurrentSolution(solutionTransformation, WorkspaceChangeKind.ProjectChanged, projectId); + } + } + + /// + public void ApplyBatchChangeToWorkspace(Action mutation) + { + ApplyBatchChangeToWorkspaceMaybeAsync(useAsync: false, mutation).VerifyCompleted(); + } + + /// + public Task ApplyBatchChangeToWorkspaceAsync(Action mutation) + { + return ApplyBatchChangeToWorkspaceMaybeAsync(useAsync: true, mutation); + } + + /// + /// Applies a change to the workspace that can do any number of project changes. + /// + /// This is needed to synchronize with to avoid any races. This + /// method could be moved down to the core Workspace layer and then could use the synchronization lock there. + public async Task ApplyBatchChangeToWorkspaceMaybeAsync(bool useAsync, Action mutation) + { + using (useAsync ? await _gate.DisposableWaitAsync().ConfigureAwait(false) : _gate.DisposableWait()) + { + var solutionChanges = new SolutionChangeAccumulator(Workspace.CurrentSolution); + mutation(solutionChanges); + + ApplyBatchChangeToWorkspace_NoLock(solutionChanges); + } + } + + private void ApplyBatchChangeToWorkspace_NoLock(SolutionChangeAccumulator solutionChanges) + { + Contract.ThrowIfFalse(_gate.CurrentCount == 0); + + if (!solutionChanges.HasChange) + return; + + Workspace.SetCurrentSolution( + _ => solutionChanges.Solution, + solutionChanges.WorkspaceChangeKind, + solutionChanges.WorkspaceChangeProjectId, + solutionChanges.WorkspaceChangeDocumentId, + onBeforeUpdate: (_, _) => + { + // Clear out mutable state not associated with the solution snapshot (for example, which documents are + // currently open). + foreach (var documentId in solutionChanges.DocumentIdsRemoved) + Workspace.ClearDocumentData(documentId); + }); + } + + private readonly Dictionary _projectReferenceInfoMap = new(); + + private ProjectReferenceInformation GetReferenceInfo_NoLock(ProjectId projectId) + { + Contract.ThrowIfFalse(_gate.CurrentCount == 0); + + return _projectReferenceInfoMap.GetOrAdd(projectId, _ => new ProjectReferenceInformation()); + } + + /// + /// Removes the project from the various maps this type maintains; it's still up to the caller to actually remove + /// the project in one way or another. + /// + internal void RemoveProjectFromTrackingMaps_NoLock(ProjectId projectId) + { + Contract.ThrowIfFalse(_gate.CurrentCount == 0); + + var project = Workspace.CurrentSolution.GetRequiredProject(projectId); + + if (_projectReferenceInfoMap.TryGetValue(projectId, out var projectReferenceInfo)) + { + // If we still had any output paths, we'll want to remove them to cause conversion back to metadata references. + // The call below implicitly is modifying the collection we've fetched, so we'll make a copy. + var solutionChanges = new SolutionChangeAccumulator(Workspace.CurrentSolution); + + foreach (var outputPath in projectReferenceInfo.OutputPaths.ToList()) + { + RemoveProjectOutputPath_NoLock(solutionChanges, projectId, outputPath); + } + + ApplyBatchChangeToWorkspace_NoLock(solutionChanges); + + _projectReferenceInfoMap.Remove(projectId); + } + + ImmutableInterlocked.TryRemove(ref _projectToMaxSupportedLangVersionMap, projectId, out _); + ImmutableInterlocked.TryRemove(ref _projectToDependencyNodeTargetIdentifier, projectId, out _); + + _onProjectRemoved?.Invoke(project); + } + + internal void RemoveSolution_NoLock() + { + Contract.ThrowIfFalse(_gate.CurrentCount == 0); + + // At this point, we should have had RemoveProjectFromTrackingMaps_NoLock called for everything else, so it's just the solution itself + // to clean up + Contract.ThrowIfFalse(_projectReferenceInfoMap.Count == 0); + Contract.ThrowIfFalse(_projectToMaxSupportedLangVersionMap.Count == 0); + Contract.ThrowIfFalse(_projectToDependencyNodeTargetIdentifier.Count == 0); + + // Create a new empty solution and set this; we will reuse the same SolutionId and path since components still may have persistence information they still need + // to look up by that location; we also keep the existing analyzer references around since those are host-level analyzers that were loaded asynchronously. + Workspace.ClearOpenDocuments(); + + Workspace.SetCurrentSolution( + solution => Workspace.CreateSolution( + SolutionInfo.Create( + SolutionId.CreateNewId(), + VersionStamp.Create(), + analyzerReferences: solution.AnalyzerReferences)), + WorkspaceChangeKind.SolutionRemoved); + } + + [PerformanceSensitive("https://github.com/dotnet/roslyn/issues/54137", AllowLocks = false)] + internal void SetMaxLanguageVersion(ProjectId projectId, string? maxLanguageVersion) + { + ImmutableInterlocked.Update( + ref _projectToMaxSupportedLangVersionMap, + static (map, arg) => map.SetItem(arg.projectId, arg.maxLanguageVersion), + (projectId, maxLanguageVersion)); + } + + [PerformanceSensitive("https://github.com/dotnet/roslyn/issues/54135", AllowLocks = false)] + internal void SetDependencyNodeTargetIdentifier(ProjectId projectId, string targetIdentifier) + { + ImmutableInterlocked.Update( + ref _projectToDependencyNodeTargetIdentifier, + static (map, arg) => map.SetItem(arg.projectId, arg.targetIdentifier), + (projectId, targetIdentifier)); + } + + private sealed class ProjectReferenceInformation + { + public readonly List OutputPaths = new(); + public readonly List<(string path, ProjectReference projectReference)> ConvertedProjectReferences = new List<(string path, ProjectReference)>(); + } + + /// + /// A multimap from an output path to the project outputting to it. Ideally, this shouldn't ever + /// actually be a true multimap, since we shouldn't have two projects outputting to the same path, but + /// any bug by a project adding the wrong output path means we could end up with some duplication. + /// In that case, we'll temporarily have two until (hopefully) somebody removes it. + /// + private readonly Dictionary> _projectsByOutputPath = new(StringComparer.OrdinalIgnoreCase); + + public void AddProjectOutputPath_NoLock(SolutionChangeAccumulator solutionChanges, ProjectId projectId, string outputPath) + { + Contract.ThrowIfFalse(_gate.CurrentCount == 0); + + var projectReferenceInformation = GetReferenceInfo_NoLock(projectId); + + projectReferenceInformation.OutputPaths.Add(outputPath); + _projectsByOutputPath.MultiAdd(outputPath, projectId); + + var projectsForOutputPath = _projectsByOutputPath[outputPath]; + var distinctProjectsForOutputPath = projectsForOutputPath.Distinct().ToList(); + + // If we have exactly one, then we're definitely good to convert + if (projectsForOutputPath.Count == 1) + { + ConvertMetadataReferencesToProjectReferences_NoLock(solutionChanges, projectId, outputPath); + } + else if (distinctProjectsForOutputPath.Count == 1) + { + // The same project has multiple output paths that are the same. Any project would have already been converted + // by the prior add, so nothing further to do + } + else + { + // We have more than one project outputting to the same path. This shouldn't happen but we'll convert back + // because now we don't know which project to reference. + foreach (var otherProjectId in projectsForOutputPath) + { + // We know that since we're adding a path to projectId and we're here that we couldn't have already + // had a converted reference to us, instead we need to convert things that are pointing to the project + // we're colliding with + if (otherProjectId != projectId) + { + ConvertProjectReferencesToMetadataReferences_NoLock(solutionChanges, otherProjectId, outputPath); + } + } + } + } + + /// + /// Attempts to convert all metadata references to to a project reference to . + /// + /// The of the project that could be referenced in place of the output path. + /// The output path to replace. + [PerformanceSensitive("https://github.com/dotnet/roslyn/issues/31306", + Constraint = "Avoid calling " + nameof(CodeAnalysis.Solution.GetProject) + " to avoid realizing all projects.")] + private void ConvertMetadataReferencesToProjectReferences_NoLock(SolutionChangeAccumulator solutionChanges, ProjectId projectIdToReference, string outputPath) + { + Contract.ThrowIfFalse(_gate.CurrentCount == 0); + + foreach (var projectIdToRetarget in solutionChanges.Solution.ProjectIds) + { + if (CanConvertMetadataReferenceToProjectReference(solutionChanges.Solution, projectIdToRetarget, referencedProjectId: projectIdToReference)) + { + // PERF: call GetProjectState instead of GetProject, otherwise creating a new project might force all + // Project instances to get created. + foreach (PortableExecutableReference reference in solutionChanges.Solution.GetProjectState(projectIdToRetarget)!.MetadataReferences) + { + if (string.Equals(reference.FilePath, outputPath, StringComparison.OrdinalIgnoreCase)) + { + FileWatchedReferenceFactory.StopWatchingReference(reference); + + var projectReference = new ProjectReference(projectIdToReference, reference.Properties.Aliases, reference.Properties.EmbedInteropTypes); + var newSolution = solutionChanges.Solution.RemoveMetadataReference(projectIdToRetarget, reference) + .AddProjectReference(projectIdToRetarget, projectReference); + + solutionChanges.UpdateSolutionForProjectAction(projectIdToRetarget, newSolution); + + GetReferenceInfo_NoLock(projectIdToRetarget).ConvertedProjectReferences.Add( + (reference.FilePath!, projectReference)); + + // We have converted one, but you could have more than one reference with different aliases + // that we need to convert, so we'll keep going + } + } + } + } + } + + [PerformanceSensitive("https://github.com/dotnet/roslyn/issues/31306", + Constraint = "Avoid calling " + nameof(CodeAnalysis.Solution.GetProject) + " to avoid realizing all projects.")] + private static bool CanConvertMetadataReferenceToProjectReference(Solution solution, ProjectId projectIdWithMetadataReference, ProjectId referencedProjectId) + { + // We can never make a project reference ourselves. This isn't a meaningful scenario, but if somebody does this by accident + // we do want to throw exceptions. + if (projectIdWithMetadataReference == referencedProjectId) + { + return false; + } + + // PERF: call GetProjectState instead of GetProject, otherwise creating a new project might force all + // Project instances to get created. + var projectWithMetadataReference = solution.GetProjectState(projectIdWithMetadataReference); + var referencedProject = solution.GetProjectState(referencedProjectId); + + Contract.ThrowIfNull(projectWithMetadataReference); + Contract.ThrowIfNull(referencedProject); + + // We don't want to convert a metadata reference to a project reference if the project being referenced isn't something + // we can create a Compilation for. For example, if we have a C# project, and it's referencing a F# project via a metadata reference + // everything would be fine if we left it a metadata reference. Converting it to a project reference means we couldn't create a Compilation + // anymore in the IDE, since the C# compilation would need to reference an F# compilation. F# projects referencing other F# projects though + // do expect this to work, and so we'll always allow references through of the same language. + if (projectWithMetadataReference.Language != referencedProject.Language) + { + if (projectWithMetadataReference.LanguageServices.GetService() != null && + referencedProject.LanguageServices.GetService() == null) + { + // We're referencing something that we can't create a compilation from something that can, so keep the metadata reference + return false; + } + } + + // If this is going to cause a circular reference, also disallow it + if (solution.GetProjectDependencyGraph().GetProjectsThatThisProjectTransitivelyDependsOn(referencedProjectId).Contains(projectIdWithMetadataReference)) + { + return false; + } + + return true; + } + + /// + /// Finds all projects that had a project reference to and convert it back to a metadata reference. + /// + /// The of the project being referenced. + /// The output path of the given project to remove the link to. + [PerformanceSensitive( + "https://github.com/dotnet/roslyn/issues/37616", + Constraint = "Update ConvertedProjectReferences in place to avoid duplicate list allocations.")] + private void ConvertProjectReferencesToMetadataReferences_NoLock(SolutionChangeAccumulator solutionChanges, ProjectId projectId, string outputPath) + { + Contract.ThrowIfFalse(_gate.CurrentCount == 0); + + foreach (var projectIdToRetarget in solutionChanges.Solution.ProjectIds) + { + var referenceInfo = GetReferenceInfo_NoLock(projectIdToRetarget); + + // Update ConvertedProjectReferences in place to avoid duplicate list allocations + for (var i = 0; i < referenceInfo.ConvertedProjectReferences.Count; i++) + { + var convertedReference = referenceInfo.ConvertedProjectReferences[i]; + + if (string.Equals(convertedReference.path, outputPath, StringComparison.OrdinalIgnoreCase) && + convertedReference.projectReference.ProjectId == projectId) + { + var metadataReference = + FileWatchedReferenceFactory.CreateReferenceAndStartWatchingFile( + convertedReference.path, + new MetadataReferenceProperties( + aliases: convertedReference.projectReference.Aliases, + embedInteropTypes: convertedReference.projectReference.EmbedInteropTypes)); + + var newSolution = solutionChanges.Solution.RemoveProjectReference(projectIdToRetarget, convertedReference.projectReference) + .AddMetadataReference(projectIdToRetarget, metadataReference); + + solutionChanges.UpdateSolutionForProjectAction(projectIdToRetarget, newSolution); + + referenceInfo.ConvertedProjectReferences.RemoveAt(i); + + // We have converted one, but you could have more than one reference with different aliases + // that we need to convert, so we'll keep going. Make sure to decrement the index so we don't + // skip any items. + i--; + } + } + } + } + + public ProjectReference? TryCreateConvertedProjectReference_NoLock(ProjectId referencingProject, string path, MetadataReferenceProperties properties) + { + // Any conversion to or from project references must be done under the global workspace lock, + // since that needs to be coordinated with updating all projects simultaneously. + Contract.ThrowIfFalse(_gate.CurrentCount == 0); + + if (_projectsByOutputPath.TryGetValue(path, out var ids) && ids.Distinct().Count() == 1) + { + var projectIdToReference = ids.First(); + + if (CanConvertMetadataReferenceToProjectReference(Workspace.CurrentSolution, referencingProject, projectIdToReference)) + { + var projectReference = new ProjectReference( + projectIdToReference, + aliases: properties.Aliases, + embedInteropTypes: properties.EmbedInteropTypes); + + GetReferenceInfo_NoLock(referencingProject).ConvertedProjectReferences.Add((path, projectReference)); + + return projectReference; + } + else + { + return null; + } + } + else + { + return null; + } + } + + public ProjectReference? TryRemoveConvertedProjectReference_NoLock(ProjectId referencingProject, string path, MetadataReferenceProperties properties) + { + // Any conversion to or from project references must be done under the global workspace lock, + // since that needs to be coordinated with updating all projects simultaneously. + Contract.ThrowIfFalse(_gate.CurrentCount == 0); + + var projectReferenceInformation = GetReferenceInfo_NoLock(referencingProject); + foreach (var convertedProject in projectReferenceInformation.ConvertedProjectReferences) + { + if (convertedProject.path == path && + convertedProject.projectReference.EmbedInteropTypes == properties.EmbedInteropTypes && + convertedProject.projectReference.Aliases.SequenceEqual(properties.Aliases)) + { + projectReferenceInformation.ConvertedProjectReferences.Remove(convertedProject); + return convertedProject.projectReference; + } + } + + return null; + } + + public void RemoveProjectOutputPath_NoLock(SolutionChangeAccumulator solutionChanges, ProjectId projectId, string outputPath) + { + Contract.ThrowIfFalse(_gate.CurrentCount == 0); + + var projectReferenceInformation = GetReferenceInfo_NoLock(projectId); + if (!projectReferenceInformation.OutputPaths.Contains(outputPath)) + { + throw new ArgumentException($"Project does not contain output path '{outputPath}'", nameof(outputPath)); + } + + projectReferenceInformation.OutputPaths.Remove(outputPath); + _projectsByOutputPath.MultiRemove(outputPath, projectId); + + // When a project is closed, we may need to convert project references to metadata references (or vice + // versa). Failure to convert the references could leave a project in the workspace with a project + // reference to a project which is not open. + // + // For the specific case where the entire solution is closing, we do not need to update the state for + // remaining projects as each project closes, because we know those projects will be closed without + // further use. Avoiding reference conversion when the solution is closing improves performance for both + // IDE close scenarios and solution reload scenarios that occur after complex branch switches. + if (!SolutionClosing) + { + if (_projectsByOutputPath.TryGetValue(outputPath, out var remainingProjectsForOutputPath)) + { + var distinctRemainingProjects = remainingProjectsForOutputPath.Distinct(); + if (distinctRemainingProjects.Count() == 1) + { + // We had more than one project outputting to the same path. Now we're back down to one + // so we can reference that one again + ConvertMetadataReferencesToProjectReferences_NoLock(solutionChanges, distinctRemainingProjects.Single(), outputPath); + } + } + else + { + // No projects left, we need to convert back to metadata references + ConvertProjectReferencesToMetadataReferences_NoLock(solutionChanges, projectId, outputPath); + } + } + } + +#pragma warning disable VSTHRD100 // Avoid async void methods + private async void StartRefreshingMetadataReferencesForFile(object? sender, string fullFilePath) +#pragma warning restore VSTHRD100 // Avoid async void methods + { + using var asyncToken = WorkspaceListener.BeginAsyncOperation(nameof(StartRefreshingMetadataReferencesForFile)); + + await ApplyBatchChangeToWorkspaceAsync(solutionChanges => + { + foreach (var project in Workspace.CurrentSolution.Projects) + { + // Loop to find each reference with the given path. It's possible that there might be multiple references of the same path; + // the project system could concievably add the same reference multiple times but with different aliases. It's also possible + // we might not find the path at all: when we receive the file changed event, we aren't checking if the file is still + // in the workspace at that time; it's possible it might have already been removed. + foreach (var portableExecutableReference in project.MetadataReferences.OfType()) + { + if (portableExecutableReference.FilePath == fullFilePath) + { + FileWatchedReferenceFactory.StopWatchingReference(portableExecutableReference); + + var newPortableExecutableReference = + FileWatchedReferenceFactory.CreateReferenceAndStartWatchingFile( + portableExecutableReference.FilePath, + portableExecutableReference.Properties); + + var newSolution = solutionChanges.Solution.RemoveMetadataReference(project.Id, portableExecutableReference) + .AddMetadataReference(project.Id, newPortableExecutableReference); + + solutionChanges.UpdateSolutionForProjectAction(project.Id, newSolution); + + } + } + } + }).ConfigureAwait(false); + } + + internal void RaiseOnDocumentsAdded(ImmutableArray filePaths) + { + _onDocumentsAdded(filePaths); + } + } +} diff --git a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectHostInfo.cs b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectHostInfo.cs new file mode 100644 index 0000000000000..0ff8335234652 --- /dev/null +++ b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectHostInfo.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; +using System.Collections.Immutable; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Host.Mef; + +namespace Microsoft.CodeAnalysis.Workspaces.ProjectSystem +{ + internal record ProjectSystemHostInfo( + ImmutableArray> DynamicFileInfoProviders, + IProjectSystemDiagnosticSource DiagnosticSource, + IHostDiagnosticAnalyzerProvider HostDiagnosticAnalyzerProvider); +} diff --git a/src/VisualStudio/Core/Def/ProjectSystem/Readme.md b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/Readme.md similarity index 61% rename from src/VisualStudio/Core/Def/ProjectSystem/Readme.md rename to src/Workspaces/Core/Portable/Workspace/ProjectSystem/Readme.md index 86d0ae5b3a6f7..7e343a2a4c643 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/Readme.md +++ b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/Readme.md @@ -2,40 +2,40 @@ There are two core types in this folder, each of which has their own lock. -Each project from the project system is represented by a VisualStudioProject which has as SemaphoreSlim _gate. This lock is taken +Each project from the project system is represented by a ProjectSystemProject which has as SemaphoreSlim _gate. This lock is taken any time a mutation happens to that individual project, to ensure that the type itself is safe to use concurrently. The expectation though is that simultaneous use from multiple threads by a project system isn't common, so no real effort has been expended to try to make the locking fine-grained there; each function just acquires the _gate and then does what it needs to do. -The workspace (VisualStudioWorkspaceImpl) also has it's own SemaphoreSlim _gate. This is acquired any time a change is being made +The project factory (ProjectSystemProjectFactory) also has it's own SemaphoreSlim _gate. This is acquired any time a change is being made to the workspace. As much as possible, try to acquire this gate in an asynchronous fashion, since during solution load this lock will have a lot of things trying to acquire it at once on a bunch of threads, and we may starve off the thread pool if we're not careful. Unfortunately however, we still have legacy project systems that aren't async friendly; they still may apply changes or batches synchronously so in those cases we still acquire the gate in a synchronous fashion. -There is a strict lock hierarchy: a VisualStudioProject may try to acquire the workspace lock while holding it's lock, -but to prevent deadlocks a holder of the VisualStudioWorkspaceImpl lock should never call a function on VisualStudioProject that +There is a strict lock hierarchy: a ProjectSystemProject may try to acquire the workspace lock while holding it's lock, +but to prevent deadlocks a holder of the ProjectSystemProjectFactory lock should never call a function on ProjectSystemProject that would acquire a project lock. To this end, a few bits of information that may seem to be "project specific" are actually stored -in maps in the VisualStudioWorkspaceImpl; specifically we maintain a list of the output paths of a project which we use to convert +in maps in the ProjectSystemProjectFactory; specifically we maintain a list of the output paths of a project which we use to convert metadata references to project references. This list is maintained in the workspace itself to avoid having to reach back to a project and ask it for information which might violate this lock hierarchy. -When a VisualStudioProject needs to make a change to the workspace, there's a number of Apply methods that can be called that +When a ProjectSystemProject needs to make a change to the workspace, there's a number of Apply methods that can be called that acquire the global workspace lock and then call a lambda to do the work that's needed. In some cases there are public methods on -VisualStudioWorkspaceImpl which are suffixed wtih _NoLock; these exist to be called inside one of these Apply methods; they all +ProjectSystemProjectFactory which are suffixed wtih _NoLock; these exist to be called inside one of these Apply methods; they all assert that the workspace lock is already being held. -There is a nested class of VisualStudioProject called BatchingDocumentCollection which manages all of logic around adding and removing +There is a nested class of ProjectSystemProject called BatchingDocumentCollection which manages all of logic around adding and removing documents, and dealing with changes. The nested class exists simply because each project has multiple sets of documents (regular documents, additional files, and .editorconfig files) that all behave the same way, so this allows for a common abstraction -to reuse most of the logic. A BatchingDocumentCollection does not have a lock of it's own, it just acquires the VisualStudioProject +to reuse most of the logic. A BatchingDocumentCollection does not have a lock of it's own, it just acquires the ProjectSystemProject lock whenever needed. There's a few ancillary types that also have their own locks: VisualStudioProjectOptionsTracker is a helper type which takes compiler command line strings and converts it to ParseOptions and -CompilationOptions. It holds onto a VisualStudioProject, and may call VisualStudioProject methods while holding it's lock. Nothing -else holds onto a VisualStudioProjectOptionsTracker that has a lock, so we avoid any deadlocks there. +CompilationOptions. It holds onto a ProjectSystemProject, and may call ProjectSystemProject methods while holding it's lock. Nothing +else holds onto a ProjectSystemProjectOptionsTracker that has a lock, so we avoid any deadlocks there. VisualStudioWorkspaceImpl has a nested type OpenFileTracker that has it's own lock to guard it's own fields. It should call nothing outside of itself while holding that lock. \ No newline at end of file diff --git a/src/VisualStudio/Core/Def/ProjectSystem/SolutionChangeAccumulator.cs b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/SolutionChangeAccumulator.cs similarity index 97% rename from src/VisualStudio/Core/Def/ProjectSystem/SolutionChangeAccumulator.cs rename to src/Workspaces/Core/Portable/Workspace/ProjectSystem/SolutionChangeAccumulator.cs index fd6566fb106c1..4285aae577177 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/SolutionChangeAccumulator.cs +++ b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/SolutionChangeAccumulator.cs @@ -2,11 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Generic; -using Microsoft.CodeAnalysis; -namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem +namespace Microsoft.CodeAnalysis.Workspaces.ProjectSystem { /// /// A little helper type to hold onto the being updated in a batch, which also diff --git a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioAnalyzer.cs b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/VisualStudioAnalyzer.cs similarity index 86% rename from src/VisualStudio/Core/Def/ProjectSystem/VisualStudioAnalyzer.cs rename to src/Workspaces/Core/Portable/Workspace/ProjectSystem/VisualStudioAnalyzer.cs index 4d72b708d3c07..2b41f36c0219e 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioAnalyzer.cs +++ b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/VisualStudioAnalyzer.cs @@ -5,15 +5,13 @@ using System; using System.Collections.Immutable; using System.IO; -using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Workspaces.ProjectSystem; -namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem +namespace Microsoft.CodeAnalysis.Workspaces.ProjectSystem { // TODO: Remove. This is only needed to support Solution Explorer Analyzer node population. // Analyzers should not be loaded in devenv process (see https://github.com/dotnet/roslyn/issues/43008). - internal sealed class VisualStudioAnalyzer : IDisposable + internal sealed class ProjectAnalyzerReference : IDisposable { // Shadow copy analyzer files coming from packages to avoid locking the files in NuGet cache. // NOTE: It is important that we share the same shadow copy assembly loader for all VisualStudioAnalyzer instances. @@ -30,7 +28,7 @@ internal sealed class VisualStudioAnalyzer : IDisposable private AnalyzerReference? _analyzerReference; private ImmutableArray _analyzerLoadErrors = ImmutableArray.Empty; - public VisualStudioAnalyzer(string fullPath, IProjectSystemDiagnosticSource projectSystemDiagnosticSource, ProjectId projectId, string language) + public ProjectAnalyzerReference(string fullPath, IProjectSystemDiagnosticSource projectSystemDiagnosticSource, ProjectId projectId, string language) { FullPath = fullPath; _projectSystemDiagnosticSource = projectSystemDiagnosticSource; @@ -58,9 +56,9 @@ public AnalyzerReference GetReference() } } - private void OnAnalyzerLoadError(object sender, AnalyzerLoadFailureEventArgs e) + private void OnAnalyzerLoadError(object? sender, AnalyzerLoadFailureEventArgs e) { - var data = DocumentAnalysisExecutor.CreateAnalyzerLoadFailureDiagnostic(e, FullPath, _projectId, _language); + var data = _projectSystemDiagnosticSource.CreateAnalyzerLoadFailureDiagnostic(e, FullPath, _projectId, _language); lock (_gate) { diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/DocumentState.cs b/src/Workspaces/Core/Portable/Workspace/Solution/DocumentState.cs index 6beeff6b668b6..3dfb1bc043b9c 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/DocumentState.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/DocumentState.cs @@ -24,8 +24,7 @@ internal partial class DocumentState : TextDocumentState { private static readonly Func s_fullParseLog = (path, mode) => $"{path} : {mode}"; - private static readonly ConditionalWeakTable s_syntaxTreeToIdMap = - new(); + private static readonly ConditionalWeakTable s_syntaxTreeToIdMap = new(); // properties inherited from the containing project: private readonly HostLanguageServices _languageServices; @@ -82,8 +81,12 @@ public DocumentState( } } + public ValueSource? TreeSource => _treeSource; + [MemberNotNullWhen(true, nameof(_treeSource))] + [MemberNotNullWhen(true, nameof(TreeSource))] [MemberNotNullWhen(true, nameof(_options))] + [MemberNotNullWhen(true, nameof(ParseOptions))] internal bool SupportsSyntaxTree => _treeSource != null; diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/DocumentState_LinkedFileReuse.cs b/src/Workspaces/Core/Portable/Workspace/Solution/DocumentState_LinkedFileReuse.cs new file mode 100644 index 0000000000000..adefbe6107513 --- /dev/null +++ b/src/Workspaces/Core/Portable/Workspace/Solution/DocumentState_LinkedFileReuse.cs @@ -0,0 +1,238 @@ +// 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.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.LanguageService; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis +{ + internal partial class DocumentState + { + /// + /// Returns a new instance of this document state that points to as the + /// text contents of the document, and which will produce a syntax tree that reuses from if possible, or which will incrementally parse the current tree to bring it up to + /// date with otherwise. + /// + public DocumentState UpdateTextAndTreeContents(ITextAndVersionSource siblingTextSource, ValueSource? siblingTreeSource) + { + if (!SupportsSyntaxTree) + { + return new DocumentState( + LanguageServices, + solutionServices, + Services, + Attributes, + _options, + siblingTextSource, + LoadTextOptions, + treeSource: null); + } + + Contract.ThrowIfNull(siblingTreeSource); + + // Always pass along the sibling text. We will always be in sync with that. + + // if a sibling tree source is provided, then we'll want to attempt to use the tree it creates, to share as + // much memory as possible with linked files. However, we can't point at that source directly. If we did, + // we'd produce the *exact* same tree-reference as another file. That would be bad as it would break the + // invariant that each document gets a unique SyntaxTree. So, instead, we produce a ValueSource that defers + // to the provided source, gets the tree from it, and then wraps its root in a new tree for us. + + // copy data from this entity, and pass to static helper, so we don't keep this green node alive. + + var filePath = this.Attributes.SyntaxTreeFilePath; + var languageServices = this.LanguageServices; + var loadTextOptions = this.LoadTextOptions; + var parseOptions = this.ParseOptions; + var textAndVersionSource = this.TextAndVersionSource; + var treeSource = this.TreeSource; + + var newTreeSource = GetReuseTreeSource( + filePath, languageServices, loadTextOptions, parseOptions, treeSource, siblingTextSource, siblingTreeSource); + + return new DocumentState( + LanguageServices, + solutionServices, + Services, + Attributes, + _options, + siblingTextSource, + LoadTextOptions, + newTreeSource); + + static AsyncLazy GetReuseTreeSource( + string filePath, + HostLanguageServices languageServices, + LoadTextOptions loadTextOptions, + ParseOptions parseOptions, + ValueSource treeSource, + ITextAndVersionSource siblingTextSource, + ValueSource siblingTreeSource) + { + return new AsyncLazy( + cancellationToken => TryReuseSiblingTreeAsync(filePath, languageServices, loadTextOptions, parseOptions, treeSource, siblingTextSource, siblingTreeSource, cancellationToken), + cancellationToken => TryReuseSiblingTree(filePath, languageServices, loadTextOptions, parseOptions, treeSource, siblingTextSource, siblingTreeSource, cancellationToken), + cacheResult: true); + } + + static bool TryReuseSiblingRoot( + string filePath, + HostLanguageServices languageServices, + LoadTextOptions loadTextOptions, + ParseOptions parseOptions, + SyntaxNode siblingRoot, + VersionStamp siblingVersion, + [NotNullWhen(true)] out TreeAndVersion? newTreeAndVersion) + { + var siblingTree = siblingRoot.SyntaxTree; + + // Look for things that disqualify us from being able to use our sibling's root. + if (!CanReuseSiblingRoot()) + { + newTreeAndVersion = null; + return false; + } + + var treeFactory = languageServices.GetRequiredService(); + + // Note: passing along siblingTree.Encoding is a bit suspect. Ideally we would only populate this tree + // with our own data (*except* for the new root). However, we think it's safe as the encoding really is + // a property of the file, and that should stay the same even if linked into multiple projects. + + var newTree = treeFactory.CreateSyntaxTree( + filePath, + parseOptions, + siblingTree.Encoding, + loadTextOptions.ChecksumAlgorithm, + siblingRoot); + + newTreeAndVersion = new TreeAndVersion(newTree, siblingVersion); + return true; + + // Determines if the root of a tree from a different project can be used in this project. The general + // intuition (explained below) is that files without `#if` directives in them can be reused as the parse + // trees will be the same. + // + // This is *technically* not completely accurate as language-version can affect the parse tree as well. + // For example, `record X() { }` is a method prior to the addition of records to the language. However, + // in practice this should not be an issue. Specifically, either user code does not have a construct + // like this, in which case they are not affected by sharing. *Or*, they do have such a construct, but + // are being deliberately pathological. In other words, there are no realistic programs that depend on + // having one interpretation in one version, and another interpretation in another version. So we are + // ok saying we don't care about having that not work in the IDE (it will still work fine in the + // compiler). + // + // Note: we deliberately do not look at language version because it often is different across project + // flavors. So we would often get no benefit to sharing if we restricted to only when the lang version + // is the same. + bool CanReuseSiblingRoot() + { + Interlocked.Increment(ref s_tryReuseSyntaxTree); + var siblingParseOptions = siblingTree.Options; + + var ppSymbolsNames1 = parseOptions.PreprocessorSymbolNames; + var ppSymbolsNames2 = siblingParseOptions.PreprocessorSymbolNames; + + // If both documents have the same preprocessor directives defined, then they'll always produce the + // same trees. So we can trivially reuse the tree from one for the other. + if (ppSymbolsNames1.SetEquals(ppSymbolsNames2)) + { + Interlocked.Increment(ref s_couldReuseBecauseOfEqualPPNames); + return true; + } + + // If the tree contains no `#` directives whatsoever, then you'll parse out the same tree and can reuse it. + if (!siblingRoot.ContainsDirectives) + { + Interlocked.Increment(ref s_couldReuseBecauseOfNoDirectives); + return true; + } + + // It's ok to contain directives like #nullable, or #region. They don't affect parsing. But if we have a + // `#if` we can't share as each side might parse this differently. + var syntaxKinds = languageServices.GetRequiredService(); + if (!siblingRoot.ContainsDirective(syntaxKinds.IfDirectiveTrivia)) + { + Interlocked.Increment(ref s_couldReuseBecauseOfNoPPDirectives); + return true; + } + + // If the tree contains a #if directive, and the pp-symbol-names are different, then the files + // absolutely may be parsed differently, and so they should not be shared. + // + // TODO(cyrusn): We could potentially be smarter here as well. We can check what pp-symbols the file + // actually uses. (e.g. 'DEBUG'/'NETCORE'/etc.) and see if the project parse options actually differ + // for these values. If not, we could reuse the trees even then. + Interlocked.Increment(ref s_couldNotReuse); + return false; + } + } + + static async Task TryReuseSiblingTreeAsync( + string filePath, + HostLanguageServices languageServices, + LoadTextOptions loadTextOptions, + ParseOptions parseOptions, + ValueSource treeSource, + ITextAndVersionSource siblingTextSource, + ValueSource siblingTreeSource, + CancellationToken cancellationToken) + { + var siblingTreeAndVersion = await siblingTreeSource.GetValueAsync(cancellationToken).ConfigureAwait(false); + var siblingTree = siblingTreeAndVersion.Tree; + + var siblingRoot = await siblingTree.GetRootAsync(cancellationToken).ConfigureAwait(false); + + if (TryReuseSiblingRoot(filePath, languageServices, loadTextOptions, parseOptions, siblingRoot, siblingTreeAndVersion.Version, out var newTreeAndVersion)) + return newTreeAndVersion; + + // Couldn't use the sibling file to get the tree contents. Instead, incrementally parse our tree to the text passed in. + return await IncrementallyParseTreeAsync(treeSource, siblingTextSource, loadTextOptions, cancellationToken).ConfigureAwait(false); + } + + static TreeAndVersion TryReuseSiblingTree( + string filePath, + HostLanguageServices languageServices, + LoadTextOptions loadTextOptions, + ParseOptions parseOptions, + ValueSource treeSource, + ITextAndVersionSource siblingTextSource, + ValueSource siblingTreeSource, + CancellationToken cancellationToken) + { + var siblingTreeAndVersion = siblingTreeSource.GetValue(cancellationToken); + var siblingTree = siblingTreeAndVersion.Tree; + + var siblingRoot = siblingTree.GetRoot(cancellationToken); + + if (TryReuseSiblingRoot(filePath, languageServices, loadTextOptions, parseOptions, siblingRoot, siblingTreeAndVersion.Version, out var newTreeAndVersion)) + return newTreeAndVersion; + + // Couldn't use the sibling file to get the tree contents. Instead, incrementally parse our tree to the text passed in. + return IncrementallyParseTree(treeSource, siblingTextSource, loadTextOptions, cancellationToken); + } + } + + // Values just kept around for benchmark tests. + private static int s_tryReuseSyntaxTree; + private static int s_couldNotReuse; + private static int s_couldReuseBecauseOfEqualPPNames; + private static int s_couldReuseBecauseOfNoDirectives; + private static int s_couldReuseBecauseOfNoPPDirectives; + + public struct TestAccessor + { + public static int TryReuseSyntaxTree => s_tryReuseSyntaxTree; + public static int CouldNotReuse => s_couldNotReuse; + public static int CouldReuseBecauseOfEqualPPNames => s_couldReuseBecauseOfEqualPPNames; + public static int CouldReuseBecauseOfNoDirectives => s_couldReuseBecauseOfNoDirectives; + public static int CouldReuseBecauseOfNoPPDirectives => s_couldReuseBecauseOfNoPPDirectives; + } + } +} diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/RecoverableTextAndVersion.cs b/src/Workspaces/Core/Portable/Workspace/Solution/RecoverableTextAndVersion.cs index 6549d09c1d7bb..ee5645a5bb545 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/RecoverableTextAndVersion.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/RecoverableTextAndVersion.cs @@ -93,7 +93,7 @@ public TextAndVersion GetValue(LoadTextOptions options, CancellationToken cancel { if (_initialSourceOrRecoverableText is ITextAndVersionSource source) { - // replace initial source with recovarable text if it hasn't been replaced already: + // replace initial source with recoverable text if it hasn't been replaced already: Interlocked.CompareExchange( ref _initialSourceOrRecoverableText, value: new RecoverableText(source, source.GetValue(options, cancellationToken), options, _services), @@ -118,7 +118,7 @@ public async Task GetValueAsync(LoadTextOptions options, Cancell { if (_initialSourceOrRecoverableText is ITextAndVersionSource source) { - // replace initial source with recovarable text if it hasn't been replaced already: + // replace initial source with recoverable text if it hasn't been replaced already: Interlocked.CompareExchange( ref _initialSourceOrRecoverableText, value: new RecoverableText(source, await source.GetValueAsync(options, cancellationToken).ConfigureAwait(false), options, _services), @@ -150,7 +150,7 @@ private sealed class RecoverableText : WeaklyCachedRecoverableValueSource(); diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/Solution.cs b/src/Workspaces/Core/Portable/Workspace/Solution/Solution.cs index ecfea4241e501..6ec45d4dfbfbc 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/Solution.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/Solution.cs @@ -1550,6 +1550,12 @@ public Solution WithDocumentSyntaxRoot(DocumentId documentId, SyntaxNode root, P return new Solution(newState); } + internal Solution WithDocumentContentsFrom(DocumentId documentId, DocumentState documentState) + { + var newState = _state.WithDocumentContentsFrom(documentId, documentState); + return newState == _state ? this : new Solution(newState); + } + /// /// Creates a new solution instance with the document specified updated to have the source /// code kind specified. diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.SkeletonReferenceCache.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.SkeletonReferenceCache.cs index 0b1bff510257e..b3bb20238bf8f 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.SkeletonReferenceCache.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.SkeletonReferenceCache.cs @@ -241,11 +241,7 @@ private bool TryReadSkeletonReferenceSetAtThisVersion(VersionStamp version, out { using var stream = SerializableBytes.CreateWritableStream(); - var optionsService = workspace.Services.GetService(); - var doNotClone = optionsService != null && optionsService.Options.DisableCloneWhenProducingSkeletonReferences; - - var compilationToEmit = doNotClone ? compilation : compilation.Clone(); - var emitResult = compilationToEmit.Emit(stream, options: s_metadataOnlyEmitOptions, cancellationToken: cancellationToken); + var emitResult = compilation.Emit(stream, options: s_metadataOnlyEmitOptions, cancellationToken: cancellationToken); if (emitResult.Success) { diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.cs index d891fd758a071..2fe88b0428291 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.cs @@ -1370,6 +1370,23 @@ public SolutionState WithDocumentSyntaxRoot(DocumentId documentId, SyntaxNode ro return UpdateDocumentState(oldDocument.UpdateTree(root, mode), contentChanged: true); } + public SolutionState WithDocumentContentsFrom(DocumentId documentId, DocumentState documentState) + { + var oldDocument = GetRequiredDocumentState(documentId); + if (oldDocument == documentState) + return this; + + if (oldDocument.TextAndVersionSource == documentState.TextAndVersionSource && + oldDocument.TreeSource == documentState.TreeSource) + { + return this; + } + + return UpdateDocumentState( + oldDocument.UpdateTextAndTreeContents(documentState.TextAndVersionSource, documentState.TreeSource), + contentChanged: true); + } + private static async Task UpdateDocumentInCompilationAsync( Compilation compilation, DocumentState oldDocument, diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/WeaklyCachedRecoverableValueSource.cs b/src/Workspaces/Core/Portable/Workspace/Solution/WeaklyCachedRecoverableValueSource.cs new file mode 100644 index 0000000000000..3b1e6a543ba56 --- /dev/null +++ b/src/Workspaces/Core/Portable/Workspace/Solution/WeaklyCachedRecoverableValueSource.cs @@ -0,0 +1,180 @@ +// 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.Shared.TestHooks; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Host +{ + /// + /// This class is a that holds onto a value weakly, but can save its value and recover + /// it on demand if needed. The value is initially strongly held, until the first time that + /// or is called. At that point, it will be dumped to secondary storage, and retrieved + /// and weakly held from that point on in the future. + /// + internal abstract class WeaklyCachedRecoverableValueSource : ValueSource where T : class + { + // enforce saving in a queue so save's don't overload the thread pool. + private static Task s_latestTask = Task.CompletedTask; + private static readonly NonReentrantLock s_taskGuard = new(); + + /// + /// Lazily created. Access via the property. + /// + private SemaphoreSlim? _lazyGate; + + /// + /// Whether or not we've saved our value to secondary storage. Used so we only do that once. + /// + private bool _saved; + + /// + /// Initial strong value that this value source is initialized with. Will be used to respond to the first + /// request to get the value, at which point it will be dumped into secondary storage. + /// + private T? _initialValue; + + /// + /// Weak reference to the value last returned from this value source. Will thus return the same value as long + /// as something external is holding onto it. + /// + private WeakReference? _weakReference; + + public WeaklyCachedRecoverableValueSource(T initialValue) + => _initialValue = initialValue; + + /// + /// Override this to save the state of the instance so it can be recovered. + /// This method will only ever be called once. + /// + protected abstract Task SaveAsync(T instance, CancellationToken cancellationToken); + + /// + /// Override this method to implement asynchronous recovery semantics. + /// This method may be called multiple times. + /// + protected abstract Task RecoverAsync(CancellationToken cancellationToken); + + /// + /// Override this method to implement synchronous recovery semantics. + /// This method may be called multiple times. + /// + protected abstract T Recover(CancellationToken cancellationToken); + + private SemaphoreSlim Gate => LazyInitialization.EnsureInitialized(ref _lazyGate, SemaphoreSlimFactory.Instance); + + /// + /// Attempts to get the value, but only through the weak reference. This will only succeed *after* the value + /// has been retrieved at least once, and has thus then been save to secondary storage. + /// + private bool TryGetWeakValue([NotNullWhen(true)] out T? value) + { + value = null; + var weakReference = _weakReference; + return weakReference != null && weakReference.TryGetTarget(out value) && value != null; + } + + /// + /// Attempts to get the value, either through our strong or weak reference. + /// + private bool TryGetStrongOrWeakValue([NotNullWhen(true)] out T? value) + { + // See if we still have the constant value stored. If so, we can trivially return that. + value = _initialValue; + if (value != null) + return true; + + // If not, see if it's something someone else is holding into, and is available through the weak-ref. + return TryGetWeakValue(out value); + } + + public override bool TryGetValue([MaybeNullWhen(false)] out T value) + => TryGetStrongOrWeakValue(out value); + + public override T GetValue(CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + + // if the value is currently being held weakly, then we can return that immediately as we know we will have + // kicked off the work to save the value to secondary storage. + if (TryGetWeakValue(out var instance)) + return instance; + + // Otherwise, we're either holding the value strongly, or we need to recover it from secondary storage. + using (Gate.DisposableWait(cancellationToken)) + { + if (!TryGetStrongOrWeakValue(out instance)) + instance = Recover(cancellationToken); + + // If the value was strongly held, kick off the work to write it to secondary storage and release the + // strong reference to it. + UpdateWeakReferenceAndEnqueueSaveTask_NoLock(instance); + return instance; + } + } + + public override async Task GetValueAsync(CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + + // if the value is currently being held weakly, then we can return that immediately as we know we will have + // kicked off the work to save the value to secondary storage. + if (TryGetWeakValue(out var instance)) + return instance; + + using (await Gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false)) + { + if (!TryGetStrongOrWeakValue(out instance)) + instance = await RecoverAsync(cancellationToken).ConfigureAwait(false); + + // If the value was strongly held, kick off the work to write it to secondary storage and release the + // strong reference to it. + UpdateWeakReferenceAndEnqueueSaveTask_NoLock(instance); + return instance; + } + } + + /// + /// Kicks off the work to save this instance to secondary storage at some point in the future. Once that save + /// occurs successfully, we will drop our cached data and return values from that storage instead. + /// + private void UpdateWeakReferenceAndEnqueueSaveTask_NoLock(T instance) + { + Contract.ThrowIfTrue(Gate.CurrentCount != 0); + + _weakReference ??= new WeakReference(instance); + _weakReference.SetTarget(instance); + + // Ensure we only save once. + if (!_saved) + { + _saved = true; + using (s_taskGuard.DisposableWait()) + { + // force all save tasks to be in sequence so we don't hog all the threads. + s_latestTask = s_latestTask.SafeContinueWithFromAsync(async _ => + { + // Now defer to our subclass to actually save the instance to secondary storage. + await SaveAsync(instance, CancellationToken.None).ConfigureAwait(false); + + // Only set _initialValue to null if the saveTask completed successfully. If the save did not complete, + // we want to keep it around to service future requests. Once we do clear out this value, then all + // future request will either retrieve the value from the weak reference (if anyone else is holding onto + // it), or will recover from underlying storage. + _initialValue = null; + }, + CancellationToken.None, + // Ensure we run continuations asynchronously so that we don't start running the continuation while + // holding s_taskGuard. + TaskContinuationOptions.RunContinuationsAsynchronously, + TaskScheduler.Default); + } + } + } + } +} diff --git a/src/Workspaces/Core/Portable/Workspace/Workspace.cs b/src/Workspaces/Core/Portable/Workspace/Workspace.cs index b196d4433f2bf..e0b276ae003e2 100644 --- a/src/Workspaces/Core/Portable/Workspace/Workspace.cs +++ b/src/Workspaces/Core/Portable/Workspace/Workspace.cs @@ -16,6 +16,7 @@ using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; @@ -36,7 +37,7 @@ public abstract partial class Workspace : IDisposable private readonly string? _workspaceKind; private readonly HostWorkspaceServices _services; - private readonly ILegacyWorkspaceOptionService _legacyOptions; + private readonly ILegacyGlobalOptionService _legacyOptions; // forces serialization of mutation calls from host (OnXXX methods). Must take this lock before taking stateLock. private readonly SemaphoreSlim _serializationLock = new(initialCount: 1); @@ -72,7 +73,7 @@ protected Workspace(HostServices host, string? workspaceKind) _services = host.CreateWorkspaceServices(this); - _legacyOptions = _services.GetRequiredService(); + _legacyOptions = _services.GetRequiredService().LegacyGlobalOptions; _legacyOptions.RegisterWorkspace(this); // queue used for sending events @@ -185,26 +186,61 @@ private protected (Solution oldSolution, Solution newSolution) SetCurrentSolutio } } + /// + internal bool SetCurrentSolution( + Func transformation, + WorkspaceChangeKind changeKind, + ProjectId? projectId = null, + DocumentId? documentId = null, + Action? onBeforeUpdate = null, + Action? onAfterUpdate = null) + { + var (updated, _) = SetCurrentSolution( + transformation, + (_, _) => changeKind, + projectId, + documentId, + onBeforeUpdate, + onAfterUpdate); + return updated; + } + /// /// Applies specified transformation to , updates to - /// the new value and raises a workspace change event of the specified kind. + /// the new value and raises a workspace change event of the specified kind. All linked documents in the + /// solution (which normally will have the same content values) will be updated to to have the same content + /// *identity*. In other words, they will point at the same instances, + /// allowing that memory to be shared. /// /// Solution transformation. - /// The kind of workspace change event to raise. - /// The id of the project updated by to be passed to the workspace change event. - /// The id of the document updated by to be passed to the workspace change event. - /// True if was set to the transformed solution, false if the transformation did not change the solution. - internal bool SetCurrentSolution( + /// The kind of workspace change event to raise. + /// The id of the project updated by to be passed to + /// the workspace change event. + /// The id of the document updated by to be passed to + /// the workspace change event. + /// True if was set to the transformed solution, false if the + /// transformation did not change the solution. + private protected (bool updated, Solution newSolution) SetCurrentSolution( Func transformation, - WorkspaceChangeKind kind, + Func changeKind, ProjectId? projectId = null, DocumentId? documentId = null, Action? onBeforeUpdate = null, Action? onAfterUpdate = null) { var (oldSolution, newSolution) = SetCurrentSolution( - transformation: static (oldSolution, data) => data.transformation(oldSolution), - data: (@this: this, transformation, onBeforeUpdate, onAfterUpdate, kind, projectId, documentId), + transformation: static (oldSolution, data) => + { + var newSolution = data.transformation(oldSolution); + + // Attempt to unify the syntax trees in the new solution (unless the option is set disabling that). + var options = oldSolution.Services.GetRequiredService().Options; + if (options.DisableSharedSyntaxTrees) + return newSolution; + + return UnifyLinkedDocumentContents(oldSolution, newSolution); + }, + data: (@this: this, transformation, onBeforeUpdate, onAfterUpdate, changeKind, projectId, documentId), onBeforeUpdate: static (oldSolution, newSolution, data) => { data.onBeforeUpdate?.Invoke(oldSolution, newSolution); @@ -216,10 +252,72 @@ internal bool SetCurrentSolution( // Queue the event but don't execute its handlers on this thread. // Doing so under the serialization lock guarantees the same ordering of the events // as the order of the changes made to the solution. - data.@this.RaiseWorkspaceChangedEventAsync(data.kind, oldSolution, newSolution, data.projectId, data.documentId); + var kind = data.changeKind(oldSolution, newSolution); + data.@this.RaiseWorkspaceChangedEventAsync(kind, oldSolution, newSolution, data.projectId, data.documentId); }); - return oldSolution != newSolution; + return (oldSolution != newSolution, newSolution); + + static Solution UnifyLinkedDocumentContents(Solution oldSolution, Solution newSolution) + { + // note: if it turns out this is too expensive, we could consider using the passed in projectId/document + // to limit the set of changes we look at. However, GetChanges *should* be fairly fast as it does + // workspace-green-node identity checks to quickly narrow down what changed. + + var changes = newSolution.GetChanges(oldSolution); + + // For all added documents, see if they link to an existing document. If so, use that existing documents text/tree. + foreach (var addedProject in changes.GetAddedProjects()) + { + foreach (var addedDocument in addedProject.Documents) + newSolution = UpdateAddedDocumentToExistingContentsInSolution(newSolution, addedDocument.Id); + } + + using var _ = PooledHashSet.GetInstance(out var seenChangedDocuments); + + foreach (var projectChanges in changes.GetProjectChanges()) + { + // Now do the same for all added documents in a project. + foreach (var addedDocument in projectChanges.GetAddedDocuments()) + newSolution = UpdateAddedDocumentToExistingContentsInSolution(newSolution, addedDocument); + + // now, for any changed document, ensure we go and make all links to it have the same text/tree. + foreach (var changedDocumentId in projectChanges.GetChangedDocuments()) + newSolution = UpdateExistingDocumentsToChangedDocumentContents(newSolution, changedDocumentId, seenChangedDocuments); + } + + return newSolution; + } + + static Solution UpdateAddedDocumentToExistingContentsInSolution(Solution solution, DocumentId addedDocumentId) + { + var relatedDocumentIds = solution.GetRelatedDocumentIds(addedDocumentId); + foreach (var relatedDocumentId in relatedDocumentIds) + { + var relatedDocument = solution.GetRequiredDocument(relatedDocumentId); + return solution.WithDocumentContentsFrom(addedDocumentId, relatedDocument.DocumentState); + } + + return solution; + } + + static Solution UpdateExistingDocumentsToChangedDocumentContents(Solution solution, DocumentId changedDocumentId, HashSet processedDocuments) + { + // Changing a document in a linked-doc-chain will end up producing N changed documents. We only want to + // process that chain once. + if (processedDocuments.Add(changedDocumentId)) + { + var changedDocument = solution.GetRequiredDocument(changedDocumentId); + var relatedDocumentIds = solution.GetRelatedDocumentIds(changedDocumentId); + foreach (var relatedDocumentId in relatedDocumentIds) + { + if (processedDocuments.Add(relatedDocumentId)) + solution = solution.WithDocumentContentsFrom(relatedDocumentId, changedDocument.DocumentState); + } + } + + return solution; + } } /// @@ -299,14 +397,14 @@ public OptionSet Options [Obsolete(@"Workspace options should be set by invoking 'workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(newOptionSet))'")] set { - var changedOptionKeys = value switch + var changedOptions = value switch { null => throw new ArgumentNullException(nameof(value)), - SolutionOptionSet serializableOptionSet => serializableOptionSet.GetChangedOptions(), + SolutionOptionSet solutionOptionSet => solutionOptionSet.GetChangedOptions(), _ => throw new ArgumentException(WorkspacesResources.Options_did_not_come_from_specified_Solution, paramName: nameof(value)) }; - _legacyOptions.SetOptions(value, changedOptionKeys); + _legacyOptions.SetOptions(changedOptions.internallyDefined, changedOptions.externallyDefined); } } @@ -780,49 +878,6 @@ protected virtual void CheckDocumentCanBeRemoved(DocumentId documentId) { } - /// - /// Call this method when the text of a document is changed on disk. - /// - protected internal void OnDocumentTextLoaderChanged(DocumentId documentId, TextLoader loader) - { - SetCurrentSolution( - oldSolution => - { - CheckDocumentIsInSolution(oldSolution, documentId); - return oldSolution.WithDocumentTextLoader(documentId, loader, PreservationMode.PreserveValue); - }, - WorkspaceChangeKind.DocumentChanged, documentId: documentId, - onAfterUpdate: (_, newSolution) => this.OnDocumentTextChanged(newSolution.GetRequiredDocument(documentId))); - } - - /// - /// Call this method when the text of a additional document is changed on disk. - /// - protected internal void OnAdditionalDocumentTextLoaderChanged(DocumentId documentId, TextLoader loader) - { - SetCurrentSolution( - oldSolution => - { - CheckAdditionalDocumentIsInSolution(oldSolution, documentId); - return oldSolution.WithAdditionalDocumentTextLoader(documentId, loader, PreservationMode.PreserveValue); - }, - WorkspaceChangeKind.AdditionalDocumentChanged, documentId: documentId); - } - - /// - /// Call this method when the text of a analyzer config document is changed on disk. - /// - protected internal void OnAnalyzerConfigDocumentTextLoaderChanged(DocumentId documentId, TextLoader loader) - { - SetCurrentSolution( - oldSolution => - { - CheckAnalyzerConfigDocumentIsInSolution(oldSolution, documentId); - return oldSolution.WithAnalyzerConfigDocumentTextLoader(documentId, loader, PreservationMode.PreserveValue); - }, - WorkspaceChangeKind.AnalyzerConfigDocumentChanged, documentId: documentId); - } - /// /// Call this method when the document info changes, such as the name, folders or file path. /// @@ -871,11 +926,9 @@ protected internal void OnDocumentTextChanged(DocumentId documentId, SourceText { OnAnyDocumentTextChanged( documentId, - newText, - mode, + (newText, mode), CheckDocumentIsInSolution, - (solution, docId) => solution.GetRelatedDocumentIds(docId), - (solution, docId, text, preservationMode) => solution.WithDocumentText(docId, text, preservationMode), + (solution, docId, newTextAndMode) => solution.WithDocumentText(docId, newTextAndMode.newText, newTextAndMode.mode), WorkspaceChangeKind.DocumentChanged, isCodeDocument: true); } @@ -887,11 +940,9 @@ protected internal void OnAdditionalDocumentTextChanged(DocumentId documentId, S { OnAnyDocumentTextChanged( documentId, - newText, - mode, + (newText, mode), CheckAdditionalDocumentIsInSolution, - (solution, docId) => ImmutableArray.Create(docId), // We do not support the concept of linked additional documents - (solution, docId, text, preservationMode) => solution.WithAdditionalDocumentText(docId, text, preservationMode), + (solution, docId, newTextAndMode) => solution.WithAdditionalDocumentText(docId, newTextAndMode.newText, newTextAndMode.mode), WorkspaceChangeKind.AdditionalDocumentChanged, isCodeDocument: false); } @@ -903,11 +954,51 @@ protected internal void OnAnalyzerConfigDocumentTextChanged(DocumentId documentI { OnAnyDocumentTextChanged( documentId, - newText, - mode, + (newText, mode), + CheckAnalyzerConfigDocumentIsInSolution, + (solution, docId, newTextAndMode) => solution.WithAnalyzerConfigDocumentText(docId, newTextAndMode.newText, newTextAndMode.mode), + WorkspaceChangeKind.AnalyzerConfigDocumentChanged, + isCodeDocument: false); + } + + /// + /// Call this method when the text of a document is changed on disk. + /// + protected internal void OnDocumentTextLoaderChanged(DocumentId documentId, TextLoader loader) + { + OnAnyDocumentTextChanged( + documentId, + loader, + CheckDocumentIsInSolution, + (solution, docId, loader) => solution.WithDocumentTextLoader(docId, loader, PreservationMode.PreserveValue), + WorkspaceChangeKind.DocumentChanged, + isCodeDocument: true); + } + + /// + /// Call this method when the text of a additional document is changed on disk. + /// + protected internal void OnAdditionalDocumentTextLoaderChanged(DocumentId documentId, TextLoader loader) + { + OnAnyDocumentTextChanged( + documentId, + loader, + CheckAdditionalDocumentIsInSolution, + (solution, docId, loader) => solution.WithAdditionalDocumentTextLoader(docId, loader, PreservationMode.PreserveValue), + WorkspaceChangeKind.AdditionalDocumentChanged, + isCodeDocument: false); + } + + /// + /// Call this method when the text of a analyzer config document is changed on disk. + /// + protected internal void OnAnalyzerConfigDocumentTextLoaderChanged(DocumentId documentId, TextLoader loader) + { + OnAnyDocumentTextChanged( + documentId, + loader, CheckAnalyzerConfigDocumentIsInSolution, - (solution, docId) => ImmutableArray.Create(docId), // We do not support the concept of linked additional documents - (solution, docId, text, preservationMode) => solution.WithAnalyzerConfigDocumentText(docId, text, preservationMode), + (solution, docId, loader) => solution.WithAnalyzerConfigDocumentTextLoader(docId, loader, PreservationMode.PreserveValue), WorkspaceChangeKind.AnalyzerConfigDocumentChanged, isCodeDocument: false); } @@ -918,13 +1009,11 @@ protected internal void OnAnalyzerConfigDocumentTextChanged(DocumentId documentI /// workspace to avoid the workspace having solutions with linked files where the contents /// do not match. /// - private void OnAnyDocumentTextChanged( + private void OnAnyDocumentTextChanged( DocumentId documentId, - SourceText newText, - PreservationMode mode, + TArg arg, Action checkIsInSolution, - Func> getRelatedDocuments, - Func updateSolutionWithText, + Func updateSolutionWithText, WorkspaceChangeKind changeKind, bool isCodeDocument) { @@ -940,20 +1029,48 @@ private void OnAnyDocumentTextChanged( data.checkIsInSolution(oldSolution, data.documentId); + // First, just update the text for the document passed in. var newSolution = oldSolution; + var previousSolution = newSolution; + newSolution = data.updateSolutionWithText(newSolution, data.documentId, data.arg); - var linkedDocuments = data.getRelatedDocuments(oldSolution, data.documentId); - foreach (var linkedDocument in linkedDocuments) + if (previousSolution != newSolution) { - var previousSolution = newSolution; - newSolution = data.updateSolutionWithText(newSolution, linkedDocument, data.newText, data.mode); - if (previousSolution != newSolution) - updatedDocumentIds.Add(linkedDocument); + updatedDocumentIds.Add(data.documentId); + + // Now go update the linked docs to have the same doc contents. + var linkedDocumentIds = oldSolution.GetRelatedDocumentIds(data.documentId); + if (linkedDocumentIds.Length > 0) + { + // Two options for updating linked docs (legacy and new). + // + // Legacy behavior: update each linked doc to point at the same SourceText instance. Each + // doc will reparse itself however it wants (and thus not share any tree contents). + // + // Modern behavior: attempt to actually have the linked documents point *into* the same + // instance data that the initial document points at. This way things like tree data can be + // shared across docs. + + var options = oldSolution.Services.GetRequiredService().Options; + var shareSyntaxTrees = !options.DisableSharedSyntaxTrees; + + var newDocument = newSolution.GetRequiredDocument(data.documentId); + foreach (var linkedDocumentId in linkedDocumentIds) + { + previousSolution = newSolution; + newSolution = shareSyntaxTrees + ? newSolution.WithDocumentContentsFrom(linkedDocumentId, newDocument.DocumentState) + : data.updateSolutionWithText(newSolution, linkedDocumentId, data.arg); + + if (previousSolution != newSolution) + updatedDocumentIds.Add(linkedDocumentId); + } + } } return newSolution; }, - data: (@this: this, documentId, newText, mode, checkIsInSolution, getRelatedDocuments, updateSolutionWithText, changeKind, isCodeDocument, updatedDocumentIds), + data: (@this: this, documentId, arg, checkIsInSolution, updateSolutionWithText, changeKind, isCodeDocument, updatedDocumentIds), onAfterUpdate: static (oldSolution, newSolution, data) => { if (data.isCodeDocument) @@ -1224,7 +1341,8 @@ internal virtual bool TryApplyChanges(Solution newSolution, IProgressTracker pro if (this.CurrentSolution.Options != newSolution.Options) { - _legacyOptions.SetOptions(newSolution.State.Options, newSolution.State.Options.GetChangedOptions()); + var changedOptions = newSolution.State.Options.GetChangedOptions(); + _legacyOptions.SetOptions(changedOptions.internallyDefined, changedOptions.externallyDefined); } if (!CurrentSolution.AnalyzerReferences.SequenceEqual(newSolution.AnalyzerReferences)) diff --git a/src/Workspaces/Core/Portable/Workspace/Workspace_Editor.cs b/src/Workspaces/Core/Portable/Workspace/Workspace_Editor.cs index a7fffb6712e92..1a84f8ad6e274 100644 --- a/src/Workspaces/Core/Portable/Workspace/Workspace_Editor.cs +++ b/src/Workspaces/Core/Portable/Workspace/Workspace_Editor.cs @@ -51,7 +51,7 @@ public abstract partial class Workspace /// internal virtual bool CanChangeActiveContextDocument => false; - private protected void ClearOpenDocuments() + internal void ClearOpenDocuments() { List docIds; using (_stateLock.DisposableWait()) diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.cs.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.cs.xlf index b7fcac4a730e8..06b13dc6b3200 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.cs.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.cs.xlf @@ -239,7 +239,7 @@ Unexpected value '{0}' in DocumentKinds array. - Unexpected value '{0}' in DocumentKinds array. + Neočekávaná hodnota {0} v poli DocumentKinds. @@ -249,7 +249,7 @@ Use 'TextDocument' property instead of 'Document' property as the provider supports non-source text documents. - Use 'TextDocument' property instead of 'Document' property as the provider supports non-source text documents. + Vlastnost TextDocument použijte místo vlastnosti Document, protože zprostředkovatel podporuje nespravované textové dokumenty. diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.de.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.de.xlf index 6bd81a75c2049..984133e4b8459 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.de.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.de.xlf @@ -239,7 +239,7 @@ Unexpected value '{0}' in DocumentKinds array. - Unexpected value '{0}' in DocumentKinds array. + Unerwarteter Wert „{0}“ im DocumentKinds-Array. @@ -249,7 +249,7 @@ Use 'TextDocument' property instead of 'Document' property as the provider supports non-source text documents. - Use 'TextDocument' property instead of 'Document' property as the provider supports non-source text documents. + Verwenden Sie die Eigenschaft „TextDocument-“ anstelle der Eigenschaft „Document“, da der Anbieter Nicht-Quelltextdokumente unterstützt. diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.es.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.es.xlf index 6fe16def0d2d9..3778c91bdb5fc 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.es.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.es.xlf @@ -239,7 +239,7 @@ Unexpected value '{0}' in DocumentKinds array. - Unexpected value '{0}' in DocumentKinds array. + Valor inesperado “{0}” en la matriz DocumentKinds. @@ -249,7 +249,7 @@ Use 'TextDocument' property instead of 'Document' property as the provider supports non-source text documents. - Use 'TextDocument' property instead of 'Document' property as the provider supports non-source text documents. + Use la propiedad “TextDocument” en lugar de la propiedad “Document” ya que el proveedor admite documentos de texto que no son de origen. diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.fr.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.fr.xlf index d97a1c935af6b..cf530c34fed87 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.fr.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.fr.xlf @@ -239,7 +239,7 @@ Unexpected value '{0}' in DocumentKinds array. - Unexpected value '{0}' in DocumentKinds array. + Valeur inattendue '{0}' dans le tableau DocumentKinds. @@ -249,7 +249,7 @@ Use 'TextDocument' property instead of 'Document' property as the provider supports non-source text documents. - Use 'TextDocument' property instead of 'Document' property as the provider supports non-source text documents. + Utilisez la propriété « TextDocument » au lieu de la propriété « Document », car le fournisseur prend en charge les documents texte non sources. diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.it.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.it.xlf index cabc4b0c179c7..cb4fa929298bd 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.it.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.it.xlf @@ -239,7 +239,7 @@ Unexpected value '{0}' in DocumentKinds array. - Unexpected value '{0}' in DocumentKinds array. + Valore imprevisto '{0}' nella matrice DocumentKinds. @@ -249,7 +249,7 @@ Use 'TextDocument' property instead of 'Document' property as the provider supports non-source text documents. - Use 'TextDocument' property instead of 'Document' property as the provider supports non-source text documents. + Usare la proprietà 'TextDocument' anziché la proprietà 'Document' perché il provider supporta documenti di testo non di origine. diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ja.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ja.xlf index ca9a9ffa011a6..9e38a2be30986 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ja.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ja.xlf @@ -239,7 +239,7 @@ Unexpected value '{0}' in DocumentKinds array. - Unexpected value '{0}' in DocumentKinds array. + DocumentKinds 配列に予期しない値 '{0}'。 @@ -249,7 +249,7 @@ Use 'TextDocument' property instead of 'Document' property as the provider supports non-source text documents. - Use 'TextDocument' property instead of 'Document' property as the provider supports non-source text documents. + プロバイダーがソース以外のテキスト ドキュメントをサポートしているため、'Document' プロパティの代わりに 'TextDocument' プロパティを使用してください。 diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ko.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ko.xlf index 4144dd4711006..bbca529ad0ab6 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ko.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ko.xlf @@ -239,7 +239,7 @@ Unexpected value '{0}' in DocumentKinds array. - Unexpected value '{0}' in DocumentKinds array. + DocumentKinds 배열에 예기치 않은 '{0}' 값이 있습니다. @@ -249,7 +249,7 @@ Use 'TextDocument' property instead of 'Document' property as the provider supports non-source text documents. - Use 'TextDocument' property instead of 'Document' property as the provider supports non-source text documents. + 공급자가 소스가 아닌 텍스트 문서를 지원하므로 'Document' 속성 대신 'TextDocument' 속성을 사용합니다. diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pl.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pl.xlf index adb6f43bb0574..82033f3929e38 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pl.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pl.xlf @@ -239,7 +239,7 @@ Unexpected value '{0}' in DocumentKinds array. - Unexpected value '{0}' in DocumentKinds array. + Nieoczekiwana wartość „{0}” w tablicy DocumentKinds. @@ -249,7 +249,7 @@ Use 'TextDocument' property instead of 'Document' property as the provider supports non-source text documents. - Use 'TextDocument' property instead of 'Document' property as the provider supports non-source text documents. + Użyj właściwości „TextDocument” zamiast właściwości „Document”, ponieważ dostawca obsługuje dokumenty tekstowe inne niż źródłowe. diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pt-BR.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pt-BR.xlf index 5746c350daeb8..9788c5f0015e5 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pt-BR.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pt-BR.xlf @@ -239,7 +239,7 @@ Unexpected value '{0}' in DocumentKinds array. - Unexpected value '{0}' in DocumentKinds array. + Valor inesperado '{0}' na matriz DocumentKinds. @@ -249,7 +249,7 @@ Use 'TextDocument' property instead of 'Document' property as the provider supports non-source text documents. - Use 'TextDocument' property instead of 'Document' property as the provider supports non-source text documents. + Use a propriedade 'TextDocument' em vez da propriedade 'Document', pois o provedor dá suporte a documentos de texto que não são de origem. diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ru.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ru.xlf index af5cba2a30667..780571c833920 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ru.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ru.xlf @@ -239,7 +239,7 @@ Unexpected value '{0}' in DocumentKinds array. - Unexpected value '{0}' in DocumentKinds array. + Непредвиденное значение "{0}" в массиве DocumentKinds. @@ -249,7 +249,7 @@ Use 'TextDocument' property instead of 'Document' property as the provider supports non-source text documents. - Use 'TextDocument' property instead of 'Document' property as the provider supports non-source text documents. + Используйте свойство "TextDocument" вместо свойства "Document", так как поставщик поддерживает текстовые документы не из источника. diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.tr.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.tr.xlf index eaa385fb63e14..07531dd0f105e 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.tr.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.tr.xlf @@ -239,7 +239,7 @@ Unexpected value '{0}' in DocumentKinds array. - Unexpected value '{0}' in DocumentKinds array. + DocumentKinds dizisinde '{0}' beklenmeyen 'değeri. @@ -249,7 +249,7 @@ Use 'TextDocument' property instead of 'Document' property as the provider supports non-source text documents. - Use 'TextDocument' property instead of 'Document' property as the provider supports non-source text documents. + Sağlayıcı kaynak olmayan metin belgelerini desteklediğinden 'Document' özelliği yerine 'TextDocument' özelliğini kullanın. diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hans.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hans.xlf index 2c2641f6906c8..3aef3b9e264f1 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hans.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hans.xlf @@ -239,7 +239,7 @@ Unexpected value '{0}' in DocumentKinds array. - Unexpected value '{0}' in DocumentKinds array. + DocumentKinds 数组中出现意外值 "{0}"。 @@ -249,7 +249,7 @@ Use 'TextDocument' property instead of 'Document' property as the provider supports non-source text documents. - Use 'TextDocument' property instead of 'Document' property as the provider supports non-source text documents. + 使用 "TextDocument" 属性而不是 "Document" 属性,因为提供程序支持非源文本文档。 diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hant.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hant.xlf index 0a5f764b96a2b..eeb354b8204ff 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hant.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hant.xlf @@ -239,7 +239,7 @@ Unexpected value '{0}' in DocumentKinds array. - Unexpected value '{0}' in DocumentKinds array. + DocumentKinds 陣列中未預期的值 '{0}'。 @@ -249,7 +249,7 @@ Use 'TextDocument' property instead of 'Document' property as the provider supports non-source text documents. - Use 'TextDocument' property instead of 'Document' property as the provider supports non-source text documents. + 使用 'TextDocument' 屬性,而不是 'Document' 屬性,因為提供者支援非來源文字文件。 diff --git a/src/Workspaces/CoreTest/CodeStyle/EditorConfigCodeStyleParserTests.cs b/src/Workspaces/CoreTest/CodeStyle/EditorConfigCodeStyleParserTests.cs index 89daaefe5a073..e4824c2f0772d 100644 --- a/src/Workspaces/CoreTest/CodeStyle/EditorConfigCodeStyleParserTests.cs +++ b/src/Workspaces/CoreTest/CodeStyle/EditorConfigCodeStyleParserTests.cs @@ -52,27 +52,20 @@ public void TestParseEditorConfigCodeStyleOption(string args, bool isEnabled, Re } [Theory] - [InlineData("never:none", (int)AccessibilityModifiersRequired.Never, ReportDiagnostic.Suppress)] - [InlineData("always:suggestion", (int)AccessibilityModifiersRequired.Always, ReportDiagnostic.Info)] - [InlineData("for_non_interface_members:warning", (int)AccessibilityModifiersRequired.ForNonInterfaceMembers, ReportDiagnostic.Warn)] - [InlineData("omit_if_default:error", (int)AccessibilityModifiersRequired.OmitIfDefault, ReportDiagnostic.Error)] - - [WorkItem(27685, "https://github.com/dotnet/roslyn/issues/27685")] - [InlineData("never : none", (int)AccessibilityModifiersRequired.Never, ReportDiagnostic.Suppress)] - [InlineData("always : suggestion", (int)AccessibilityModifiersRequired.Always, ReportDiagnostic.Info)] - [InlineData("for_non_interface_members : warning", (int)AccessibilityModifiersRequired.ForNonInterfaceMembers, ReportDiagnostic.Warn)] - [InlineData("omit_if_default : error", (int)AccessibilityModifiersRequired.OmitIfDefault, ReportDiagnostic.Error)] - public void TestParseEditorConfigAccessibilityModifiers(string args, int value, ReportDiagnostic severity) + [InlineData("never:none", AccessibilityModifiersRequired.Never, ReportDiagnostic.Suppress)] + [InlineData("always:suggestion", AccessibilityModifiersRequired.Always, ReportDiagnostic.Info)] + [InlineData("for_non_interface_members:warning", AccessibilityModifiersRequired.ForNonInterfaceMembers, ReportDiagnostic.Warn)] + [InlineData("omit_if_default:error", AccessibilityModifiersRequired.OmitIfDefault, ReportDiagnostic.Error)] + [InlineData("never : none", AccessibilityModifiersRequired.Never, ReportDiagnostic.Suppress), WorkItem(27685, "https://github.com/dotnet/roslyn/issues/27685")] + [InlineData("always : suggestion", AccessibilityModifiersRequired.Always, ReportDiagnostic.Info)] + [InlineData("for_non_interface_members : warning", AccessibilityModifiersRequired.ForNonInterfaceMembers, ReportDiagnostic.Warn)] + [InlineData("omit_if_default : error", AccessibilityModifiersRequired.OmitIfDefault, ReportDiagnostic.Error)] + internal void TestParseEditorConfigAccessibilityModifiers(string configurationString, AccessibilityModifiersRequired value, ReportDiagnostic severity) { - var storageLocation = CodeStyleOptions2.AccessibilityModifiersRequired.StorageLocations - .OfType>>() - .Single(); - var allRawConventions = StructuredAnalyzerConfigOptions.Create(DictionaryAnalyzerConfigOptions.EmptyDictionary.Add(storageLocation.KeyName, args)); + Assert.True(CodeStyleOptions2.AccessibilityModifiersRequired.Definition.Serializer.TryParseValue(configurationString, out var parsedCodeStyleOption)); - Assert.True(storageLocation.TryGetOption(allRawConventions, typeof(CodeStyleOption2), out var parsedCodeStyleOption)); - var codeStyleOption = (CodeStyleOption2)parsedCodeStyleOption!; - Assert.Equal((AccessibilityModifiersRequired)value, codeStyleOption.Value); - Assert.Equal(severity, codeStyleOption.Notification.Severity); + Assert.Equal(value, parsedCodeStyleOption!.Value); + Assert.Equal(severity, parsedCodeStyleOption.Notification.Severity); } [Theory] @@ -86,13 +79,8 @@ public void TestParseEditorConfigAccessibilityModifiers(string args, int value, [InlineData(" crlf ", "\r\n")] public void TestParseEditorConfigEndOfLine(string configurationString, string newLine) { - var storageLocation = FormattingOptions.NewLine.StorageLocations - .OfType>() - .Single(); - var allRawConventions = StructuredAnalyzerConfigOptions.Create(DictionaryAnalyzerConfigOptions.EmptyDictionary.Add(storageLocation.KeyName, configurationString)); - - Assert.True(storageLocation.TryGetOption(allRawConventions, typeof(string), out var parsedNewLine)); - Assert.Equal(newLine, (string?)parsedNewLine); + Assert.True(FormattingOptions2.NewLine.Definition.Serializer.TryParseValue(configurationString, out var parsedNewLine)); + Assert.Equal(newLine, parsedNewLine); } } } diff --git a/src/Workspaces/CoreTest/EditorConfigStorageLocation/NamingStylePreferenceEditorConfigStorageLocationTests.cs b/src/Workspaces/CoreTest/EditorConfigStorageLocation/NamingStylePreferenceEditorConfigStorageLocationTests.cs index 28d71b7effce5..d4c93ec758704 100644 --- a/src/Workspaces/CoreTest/EditorConfigStorageLocation/NamingStylePreferenceEditorConfigStorageLocationTests.cs +++ b/src/Workspaces/CoreTest/EditorConfigStorageLocation/NamingStylePreferenceEditorConfigStorageLocationTests.cs @@ -2,16 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - -using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; -using Microsoft.CodeAnalysis.Options; -using Roslyn.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.UnitTests.EditorConfig.StorageLocation @@ -21,15 +14,14 @@ public class NamingStylePreferenceEditorConfigStorageLocationTests [Fact] public static void TestEmptyDictionaryReturnNoNamingStylePreferencesObjectReturnsFalse() { - var editorConfigStorageLocation = new NamingStylePreferenceEditorConfigStorageLocation(); - var result = editorConfigStorageLocation.TryGetOption(StructuredAnalyzerConfigOptions.Create(DictionaryAnalyzerConfigOptions.EmptyDictionary), typeof(NamingStylePreferences), out _); - Assert.False(result, "Expected TryParseReadonlyDictionary to return 'false' for empty dictionary"); + var options = StructuredAnalyzerConfigOptions.Create(DictionaryAnalyzerConfigOptions.EmptyDictionary); + var value = options.GetNamingStylePreferences(); + Assert.True(value.IsEmpty); } [Fact] public static void TestNonEmptyDictionaryReturnsTrue() { - var editorConfigStorageLocation = new NamingStylePreferenceEditorConfigStorageLocation(); var options = StructuredAnalyzerConfigOptions.Create(new Dictionary() { ["dotnet_naming_rule.methods_and_properties_must_be_pascal_case.severity"] = "error", @@ -40,21 +32,8 @@ public static void TestNonEmptyDictionaryReturnsTrue() ["dotnet_naming_style.pascal_case_style.capitalization"] = "pascal_case" }.ToImmutableDictionary(AnalyzerConfigOptions.KeyComparer)); - var result = editorConfigStorageLocation.TryGetOption(options, typeof(NamingStylePreferences), out var value); - - Assert.True(result, "Expected non-empty dictionary to return true"); - var namingStylePreferences = Assert.IsAssignableFrom(value); - Assert.Equal(ReportDiagnostic.Error, namingStylePreferences.Rules.NamingRules[0].EnforcementLevel); - } - - [Fact] - public static void TestObjectTypeThrowsInvalidOperationException() - { - var editorConfigStorageLocation = new NamingStylePreferenceEditorConfigStorageLocation(); - Assert.Throws(() => - { - editorConfigStorageLocation.TryGetOption(StructuredAnalyzerConfigOptions.Create(DictionaryAnalyzerConfigOptions.EmptyDictionary), typeof(object), out var @object); - }); + var value = options.GetNamingStylePreferences(); + Assert.Equal(ReportDiagnostic.Error, value.Rules.NamingRules[0].EnforcementLevel); } } } diff --git a/src/Workspaces/CoreTest/Formatter/FormatterTests.cs b/src/Workspaces/CoreTest/Formatter/FormatterTests.cs index 759c36afa571f..88501b53c1953 100644 --- a/src/Workspaces/CoreTest/Formatter/FormatterTests.cs +++ b/src/Workspaces/CoreTest/Formatter/FormatterTests.cs @@ -83,7 +83,7 @@ public async Task FormatAsync_ForeignLanguageWithFormattingSupport_Options(bool Assert.Equal(7, documentOptions.GetOption(FormattingOptions.IndentationSize)); #pragma warning restore - var options = passExplicitOptions ? new OptionValueSet(ImmutableDictionary.Empty. + var options = passExplicitOptions ? new TestOptionSet(ImmutableDictionary.Empty. Add(new OptionKey(FormattingOptions.UseTabs, NoCompilationConstants.LanguageName), true). Add(new OptionKey(FormattingOptions.TabSize, NoCompilationConstants.LanguageName), 5). Add(new OptionKey(FormattingOptions.IndentationSize, NoCompilationConstants.LanguageName), 6). @@ -118,7 +118,7 @@ public async Task PublicOptions() // Validate that options are read from specified OptionSet: - var updatedOptions = OptionsTestHelpers.GetOptionSetWithChangedOptions(OptionValueSet.Empty, OptionsTestHelpers.PublicFormattingOptionsWithNonDefaultValues); + var updatedOptions = OptionsTestHelpers.GetOptionSetWithChangedOptions(TestOptionSet.Empty, OptionsTestHelpers.PublicFormattingOptionsWithNonDefaultValues); ValidateCSharpOptions((CSharpSyntaxFormattingOptions)(await Formatter.GetFormattingOptionsAsync(csDocument, updatedOptions, CancellationToken.None)).Syntax!); ValidateVisualBasicOptions((VisualBasicSyntaxFormattingOptions)(await Formatter.GetFormattingOptionsAsync(vbDocument, updatedOptions, CancellationToken.None)).Syntax!); diff --git a/src/Workspaces/CoreTest/Options/DocumentOptionSetTests.cs b/src/Workspaces/CoreTest/Options/DocumentOptionSetTests.cs new file mode 100644 index 0000000000000..c7efa6579829b --- /dev/null +++ b/src/Workspaces/CoreTest/Options/DocumentOptionSetTests.cs @@ -0,0 +1,173 @@ +// 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.CodeStyle; +using Microsoft.CodeAnalysis.CSharp.Formatting; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Recommendations; +using Microsoft.CodeAnalysis.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.UnitTests.Options; + +public sealed class DocumentOptionSetTests +{ + [Fact] + public void GetOption() + { + var underlyingSet = new TestOptionSet(ImmutableDictionary.Empty.Add( + new OptionKey(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInMemberAccess, LanguageNames.CSharp), + new CodeStyleOption2(true, NotificationOption2.Error))); + + var configOptions = StructuredAnalyzerConfigOptions.Create(ImmutableDictionary.Create(AnalyzerConfigOptions.KeyComparer).Add( + "dotnet_style_qualification_for_event", "true:warning")); + + var set = new DocumentOptionSet(configOptions, underlyingSet, LanguageNames.CSharp); + + // option stored in analyzer config: + Assert.Equal(new CodeStyleOption(true, NotificationOption.Warning), set.GetOption(CodeStyleOptions.QualifyEventAccess, LanguageNames.CSharp)); + + // cache hit: + Assert.Equal(new CodeStyleOption(true, NotificationOption.Warning), set.GetOption(CodeStyleOptions.QualifyEventAccess, LanguageNames.CSharp)); + + // option stored in underlying config: + Assert.Equal(new CodeStyleOption(true, NotificationOption.Error), set.GetOption(CodeStyleOptions.PreferIntrinsicPredefinedTypeKeywordInMemberAccess, LanguageNames.CSharp)); + + // cache hit: + Assert.Equal(new CodeStyleOption(true, NotificationOption.Error), set.GetOption(CodeStyleOptions.PreferIntrinsicPredefinedTypeKeywordInMemberAccess, LanguageNames.CSharp)); + + // public option that has no editorconfig storage: + Assert.Equal(RecommendationOptions.FilterOutOfScopeLocals.DefaultValue, set.GetOption(RecommendationOptions.FilterOutOfScopeLocals, LanguageNames.CSharp)); + } + + [Fact] + public void GetOption_NoConfigOptions() + { + var underlyingSet = new TestOptionSet(ImmutableDictionary.Empty.Add( + new OptionKey(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInMemberAccess, LanguageNames.CSharp), + new CodeStyleOption2(true, NotificationOption2.Error))); + + var set = new DocumentOptionSet(configOptions: null, underlyingSet, LanguageNames.CSharp); + + // option stored in analyzer config: + Assert.Equal(CodeStyleOptions.QualifyEventAccess.DefaultValue, set.GetOption(CodeStyleOptions.QualifyEventAccess, LanguageNames.CSharp)); + + // cache hit: + Assert.Equal(CodeStyleOptions.QualifyEventAccess.DefaultValue, set.GetOption(CodeStyleOptions.QualifyEventAccess, LanguageNames.CSharp)); + + // option stored in underlying config: + Assert.Equal(new CodeStyleOption(true, NotificationOption.Error), set.GetOption(CodeStyleOptions.PreferIntrinsicPredefinedTypeKeywordInMemberAccess, LanguageNames.CSharp)); + + // cache hit: + Assert.Equal(new CodeStyleOption(true, NotificationOption.Error), set.GetOption(CodeStyleOptions.PreferIntrinsicPredefinedTypeKeywordInMemberAccess, LanguageNames.CSharp)); + } + + [Fact] + public void InternalPublicValueMapping() + { + var underlyingSet = new TestOptionSet(ImmutableDictionary.Empty); + var set = new DocumentOptionSet(configOptions: null, underlyingSet, LanguageNames.CSharp); + + var newValue = new CodeStyleOption(true, NotificationOption.Error); + var optionKey = new OptionKey(CodeStyleOptions.PreferIntrinsicPredefinedTypeKeywordInMemberAccess, LanguageNames.CSharp); + var updatedSet = set.WithChangedOption(optionKey, newValue); + + Assert.IsType>(updatedSet.GetInternalOptionValue(optionKey)); + + var actualValue = updatedSet.GetOption(optionKey); + Assert.IsType>(actualValue); + Assert.Equal(newValue, actualValue); + } + + [Fact] + public void InternalStorageMapping_NewLineBeforeOpenBrace() + { + var underlyingSet = new TestOptionSet(ImmutableDictionary.Empty); + var set = new DocumentOptionSet(configOptions: null, underlyingSet, LanguageNames.CSharp); + + var option = CSharpFormattingOptions2.NewLineBeforeOpenBrace; + + foreach (var (legacyOption, flag) in new[] + { + (CSharpFormattingOptions.NewLinesForBracesInTypes, NewLineBeforeOpenBracePlacement.Types), + (CSharpFormattingOptions.NewLinesForBracesInMethods, NewLineBeforeOpenBracePlacement.Methods), + (CSharpFormattingOptions.NewLinesForBracesInProperties, NewLineBeforeOpenBracePlacement.Properties), + (CSharpFormattingOptions.NewLinesForBracesInAccessors, NewLineBeforeOpenBracePlacement.Accessors), + (CSharpFormattingOptions.NewLinesForBracesInAnonymousMethods, NewLineBeforeOpenBracePlacement.AnonymousMethods), + (CSharpFormattingOptions.NewLinesForBracesInControlBlocks, NewLineBeforeOpenBracePlacement.ControlBlocks), + (CSharpFormattingOptions.NewLinesForBracesInAnonymousTypes, NewLineBeforeOpenBracePlacement.AnonymousTypes), + (CSharpFormattingOptions.NewLinesForBracesInObjectCollectionArrayInitializers, NewLineBeforeOpenBracePlacement.ObjectCollectionArrayInitializers), + (CSharpFormattingOptions.NewLinesForBracesInLambdaExpressionBody, NewLineBeforeOpenBracePlacement.LambdaExpressionBody), + }) + { + var newValue = !legacyOption.DefaultValue; + var optionKey = new OptionKey(legacyOption); + var updatedSet = set.WithChangedOption(optionKey, newValue); + + var newInternalValue = option.DefaultValue.WithFlagValue(flag, newValue); + + Assert.Equal(newInternalValue, updatedSet.GetInternalOptionValue(new OptionKey(option))); + Assert.Equal(newValue, updatedSet.GetOption(optionKey)); + } + } + + [Fact] + public void InternalStorageMapping_NewLineBeforeOpenBrace_Config() + { + var underlyingSet = new TestOptionSet(ImmutableDictionary.Empty + .Add(new OptionKey(CSharpFormattingOptions.NewLinesForBracesInTypes), false) + .Add(new OptionKey(CSharpFormattingOptions.NewLinesForBracesInAccessors), true) + .Add(new OptionKey(CSharpFormattingOptions.NewLinesForBracesInAnonymousMethods), false)); + + var configOptions = StructuredAnalyzerConfigOptions.Create(ImmutableDictionary.Create(AnalyzerConfigOptions.KeyComparer).Add( + "csharp_new_line_before_open_brace", "types,methods")); + + var set = new DocumentOptionSet(configOptions, underlyingSet, LanguageNames.CSharp); + + // editor config value overrides all values of the enum stored in the underlying set: + Assert.True((bool?)set.GetOption(new OptionKey(CSharpFormattingOptions.NewLinesForBracesInTypes))); + Assert.True((bool?)set.GetOption(new OptionKey(CSharpFormattingOptions.NewLinesForBracesInMethods))); + Assert.False((bool?)set.GetOption(new OptionKey(CSharpFormattingOptions.NewLinesForBracesInAccessors))); + Assert.False((bool?)set.GetOption(new OptionKey(CSharpFormattingOptions.NewLinesForBracesInAnonymousMethods))); + Assert.False((bool?)set.GetOption(new OptionKey(CSharpFormattingOptions.NewLinesForBracesInProperties))); + + var updatedSet = set.WithChangedOption(new OptionKey(CSharpFormattingOptions.NewLinesForBracesInProperties), true); + + Assert.True((bool?)updatedSet.GetOption(new OptionKey(CSharpFormattingOptions.NewLinesForBracesInTypes))); + Assert.True((bool?)updatedSet.GetOption(new OptionKey(CSharpFormattingOptions.NewLinesForBracesInMethods))); + Assert.False((bool?)updatedSet.GetOption(new OptionKey(CSharpFormattingOptions.NewLinesForBracesInAccessors))); + Assert.False((bool?)updatedSet.GetOption(new OptionKey(CSharpFormattingOptions.NewLinesForBracesInAnonymousMethods))); + Assert.True((bool?)updatedSet.GetOption(new OptionKey(CSharpFormattingOptions.NewLinesForBracesInProperties))); + } + + [Fact] + public void InternalStorageMapping_SpaceBetweenParentheses() + { + var underlyingSet = new TestOptionSet(ImmutableDictionary.Empty); + var set = new DocumentOptionSet(configOptions: null, underlyingSet, LanguageNames.CSharp); + + var option = CSharpFormattingOptions2.SpaceBetweenParentheses; + + foreach (var (legacyOption, flag) in new[] + { + (CSharpFormattingOptions.SpaceWithinExpressionParentheses, SpacePlacementWithinParentheses.Expressions), + (CSharpFormattingOptions.SpaceWithinCastParentheses, SpacePlacementWithinParentheses.TypeCasts), + (CSharpFormattingOptions.SpaceWithinOtherParentheses, SpacePlacementWithinParentheses.ControlFlowStatements), + }) + { + var newValue = !legacyOption.DefaultValue; + var optionKey = new OptionKey(legacyOption); + var updatedSet = set.WithChangedOption(optionKey, newValue); + + var newInternalValue = option.DefaultValue.WithFlagValue(flag, newValue); + + Assert.Equal(newInternalValue, updatedSet.GetInternalOptionValue(new OptionKey(option))); + Assert.Equal(newValue, updatedSet.GetOption(optionKey)); + } + } +} diff --git a/src/Workspaces/CoreTest/Options/OptionKeyTests.cs b/src/Workspaces/CoreTest/Options/OptionKeyTests.cs index d2c109ce29f9b..7b51e92be1dc4 100644 --- a/src/Workspaces/CoreTest/Options/OptionKeyTests.cs +++ b/src/Workspaces/CoreTest/Options/OptionKeyTests.cs @@ -3,21 +3,29 @@ // See the LICENSE file in the project root for more information. using System; +using System.Linq; +using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Formatting; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.UnitTests; using Xunit; -namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Options +namespace Microsoft.CodeAnalysis.UnitTests.Options { public class OptionKeyTests { + private sealed class TestOptionStorageLocation : OptionStorageLocation + { + } + [Fact] public void OptionConstructor_Errors() { Assert.Throws(() => new Option("Test Feature", null!, false)); Assert.Throws(() => new Option(null!, "Test Name", false)); Assert.Throws(() => new Option("X", "Test Name", false, storageLocations: null!)); + Assert.Throws(() => new Option("X", "Test Name", false, storageLocations: new OptionStorageLocation[] { null! })); } [Fact] @@ -26,6 +34,62 @@ public void PerLanguageOptionConstructor_Errors() Assert.Throws(() => new PerLanguageOption("Test Feature", null!, false)); Assert.Throws(() => new PerLanguageOption(null!, "Test Name", false)); Assert.Throws(() => new PerLanguageOption("X", "Test Name", false, storageLocations: null!)); + Assert.Throws(() => new PerLanguageOption("X", "Test Name", false, storageLocations: new OptionStorageLocation[] { null! })); + } + + [Fact] + public void OptionConstructor_MultipleStorages() + { + var storage1 = new TestOptionStorageLocation(); + var storage2 = new TestOptionStorageLocation(); + var storage3 = new TestOptionStorageLocation(); + + var option = new Option("X", "Test Name", false, storage1, storage2, storage3); + Assert.Same(storage1, option.StorageLocations[0]); + Assert.Same(storage2, option.StorageLocations[1]); + Assert.Same(storage3, option.StorageLocations[2]); + } + + [Fact] + public void PerLanguageOptionConstructor_MultipleStorages() + { + var storage1 = new TestOptionStorageLocation(); + var storage2 = new TestOptionStorageLocation(); + var storage3 = new TestOptionStorageLocation(); + + var option = new PerLanguageOption("X", "Test Name", false, storage1, storage2, storage3); + Assert.Same(storage1, option.StorageLocations[0]); + Assert.Same(storage2, option.StorageLocations[1]); + Assert.Same(storage3, option.StorageLocations[2]); + } + + [Fact] + public void Ctor_Language() + { + var optionKey = new OptionKey(new TestOption() { IsPerLanguage = false }); + Assert.Null(optionKey.Language); + + Assert.Throws(() => new OptionKey(null!)); + Assert.Throws(() => new OptionKey(null!, null!)); + Assert.Throws(() => new OptionKey(null!, "lang")); + Assert.Throws(() => new OptionKey(new TestOption() { IsPerLanguage = true })); + Assert.Throws(() => new OptionKey(new TestOption() { IsPerLanguage = false }, language: "lang")); + } + + [Fact] + public void Names() + { + var option1 = new Option2(name: "name", defaultValue: false); + Assert.Equal("config", ((IOption)option1).Feature); + Assert.Equal("name", ((IOption)option1).Name); + Assert.Equal("name", option1.Definition.ConfigName); + Assert.Equal("name", option1.ToString()); + + var option2 = new PerLanguageOption2(name: "name", defaultValue: false); + Assert.Equal("config", ((IOption)option2).Feature); + Assert.Equal("name", ((IOption)option2).Name); + Assert.Equal("name", option2.Definition.ConfigName); + Assert.Equal("name", option2.ToString()); } [Fact] @@ -99,5 +163,29 @@ public void Equals_Option_NonUniqueConfigName() Assert.False(CSharpFormattingOptions.SpacingAfterMethodDeclarationName.Equals(option3)); Assert.False(option3.Equals(CSharpFormattingOptions.SpacingAfterMethodDeclarationName)); } + + [Fact] + public void ToPublicOption() + { + var option = CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInMemberAccess; + var publicOption = CodeStyleOptions.PreferIntrinsicPredefinedTypeKeywordInMemberAccess; + + Assert.True(option.Definition.Serializer.TryParseValue("true:suggestion", out var result)); + Assert.Equal(new CodeStyleOption2(true, NotificationOption2.Suggestion), result); + + Assert.Empty(publicOption.StorageLocations); + } + + [Fact] + public void IsEditorConfigOption() + { + Assert.All(FormattingOptions2.Options, o => Assert.True(o.Definition.IsEditorConfigOption)); + Assert.False(FormattingOptions2.SmartIndent.Definition.IsEditorConfigOption); + + Assert.All(CSharpFormattingOptions2.AllOptions, o => Assert.True(o.Definition.IsEditorConfigOption)); + + Assert.True(NamingStyleOptions.NamingPreferences.Definition.IsEditorConfigOption); + Assert.True(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInMemberAccess.Definition.IsEditorConfigOption); + } } } diff --git a/src/Workspaces/CoreTest/Simplifier/SimplifierTests.cs b/src/Workspaces/CoreTest/Simplifier/SimplifierTests.cs index 08d85b61bdc87..1956e62a97335 100644 --- a/src/Workspaces/CoreTest/Simplifier/SimplifierTests.cs +++ b/src/Workspaces/CoreTest/Simplifier/SimplifierTests.cs @@ -108,17 +108,12 @@ static OptionSet GetOptionSetWithChangedPublicOptions(OptionSet options) (CodeStyleOptions.QualifyEventAccess, false), (CodeStyleOptions.PreferIntrinsicPredefinedTypeKeywordInMemberAccess, false), (CodeStyleOptions.PreferIntrinsicPredefinedTypeKeywordInDeclaration, false), - (CSharpCodeStyleOptions.VarForBuiltInTypes, false), - (CSharpCodeStyleOptions.VarWhenTypeIsApparent, false), - (CSharpCodeStyleOptions.VarElsewhere, false), - (CSharpCodeStyleOptions.PreferSimpleDefaultExpression, false), - (CSharpCodeStyleOptions.PreferBraces, PreferBracesPreference.WhenMultiline), }; var updatedOptions = options; foreach (var (option, newValue) in publicOptions) { - var languages = (option is IPerLanguageValuedOption) ? new[] { LanguageNames.CSharp, LanguageNames.VisualBasic } : new string?[] { null }; + var languages = option.IsPerLanguage ? new[] { LanguageNames.CSharp, LanguageNames.VisualBasic } : new string?[] { null }; foreach (var language in languages) { @@ -144,12 +139,6 @@ static void ValidateCommonOptions(SimplifierOptions simplifierOptions) static void ValidateCSharpOptions(CSharpSimplifierOptions simplifierOptions) { ValidateCommonOptions(simplifierOptions); - - Assert.False(simplifierOptions.VarForBuiltInTypes.Value); - Assert.False(simplifierOptions.VarWhenTypeIsApparent.Value); - Assert.False(simplifierOptions.VarElsewhere.Value); - Assert.False(simplifierOptions.PreferSimpleDefaultExpression.Value); - Assert.Equal(PreferBracesPreference.WhenMultiline, simplifierOptions.PreferBraces.Value); } static void ValidateVisualBasicOptions(VisualBasicSimplifierOptions simplifierOptions) diff --git a/src/Workspaces/CoreTest/SolutionTests/SolutionTests.cs b/src/Workspaces/CoreTest/SolutionTests/SolutionTests.cs index 1be56118a8360..f15e4ad676530 100644 --- a/src/Workspaces/CoreTest/SolutionTests/SolutionTests.cs +++ b/src/Workspaces/CoreTest/SolutionTests/SolutionTests.cs @@ -60,6 +60,32 @@ private static Workspace CreateWorkspaceWithProjectAndDocuments() return workspace; } + private static Workspace CreateWorkspaceWithProjectAndLinkedDocuments( + string docContents, ParseOptions? parseOptions1 = null, ParseOptions? parseOptions2 = null) + { + parseOptions1 ??= CSharpParseOptions.Default; + parseOptions2 ??= CSharpParseOptions.Default; + var projectId1 = ProjectId.CreateNewId(); + var projectId2 = ProjectId.CreateNewId(); + + var workspace = CreateWorkspace(); + + // note: despite the additional-doc and analyzer-config doc being at the same path in multiple projects, + // they will still be treated as unique as the workspace only has the concept of linked docs for normal + // docs. + Assert.True(workspace.TryApplyChanges(workspace.CurrentSolution + .AddProject(projectId1, "proj1", "proj1.dll", LanguageNames.CSharp).WithProjectParseOptions(projectId1, parseOptions1) + .AddDocument(DocumentId.CreateNewId(projectId1), "goo.cs", SourceText.From(docContents, Encoding.UTF8, SourceHashAlgorithms.Default), filePath: "goo.cs") + .AddAdditionalDocument(DocumentId.CreateNewId(projectId1), "add.txt", SourceText.From("text", Encoding.UTF8, SourceHashAlgorithms.Default), filePath: "add.txt") + .AddAnalyzerConfigDocument(DocumentId.CreateNewId(projectId1), "editorcfg", SourceText.From("config", Encoding.UTF8, SourceHashAlgorithms.Default), filePath: "/a/b") + .AddProject(projectId2, "proj2", "proj2.dll", LanguageNames.CSharp).WithProjectParseOptions(projectId2, parseOptions2) + .AddDocument(DocumentId.CreateNewId(projectId2), "goo.cs", SourceText.From(docContents, Encoding.UTF8, SourceHashAlgorithms.Default), filePath: "goo.cs") + .AddAdditionalDocument(DocumentId.CreateNewId(projectId2), "add.txt", SourceText.From("text", Encoding.UTF8, SourceHashAlgorithms.Default), filePath: "add.txt") + .AddAnalyzerConfigDocument(DocumentId.CreateNewId(projectId2), "editorcfg", SourceText.From("config", Encoding.UTF8, SourceHashAlgorithms.Default), filePath: "/a/b"))); + + return workspace; + } + private static IEnumerable EmptyEnumerable() { yield break; @@ -363,6 +389,416 @@ public void WithDocumentText_MultipleDocuments() Assert.Throws(() => solution.WithDocumentText(new[] { documentId }, text, (PreservationMode)(-1))); } + public enum TextUpdateType + { + SourceText, + TextLoader, + TextAndVersion, + } + + [Theory, CombinatorialData] + public async Task WithDocumentText_LinkedFiles( + PreservationMode mode, + TextUpdateType updateType) + { + using var workspace = CreateWorkspaceWithProjectAndLinkedDocuments("public class Goo { }"); + var solution = workspace.CurrentSolution; + + var documentId1 = solution.Projects.First().DocumentIds.Single(); + var documentId2 = solution.Projects.Last().DocumentIds.Single(); + + var document1 = solution.GetRequiredDocument(documentId1); + var document2 = solution.GetRequiredDocument(documentId2); + + var text1 = await document1.GetTextAsync(); + var text2 = await document2.GetTextAsync(); + var version1 = await document1.GetTextVersionAsync(); + var version2 = await document2.GetTextVersionAsync(); + var root1 = await document1.GetRequiredSyntaxRootAsync(CancellationToken.None); + var root2 = await document2.GetRequiredSyntaxRootAsync(CancellationToken.None); + + Assert.Equal(text1.ToString(), text2.ToString()); + Assert.Equal(version1, version2); + + // We get different red nodes, but they should be backed by the same green nodes. + Assert.NotEqual(root1, root2); + Assert.True(root1.IsIncrementallyIdenticalTo(root2)); + + var text = SourceText.From("new text", encoding: null, SourceHashAlgorithm.Sha1); + var textAndVersion = TextAndVersion.Create(text, VersionStamp.Create()); + solution = UpdateSolution(mode, updateType, solution, documentId1, text, textAndVersion); + + // because we only forked one doc, the text/versions should be different in this interim solution. + + document1 = solution.GetRequiredDocument(documentId1); + document2 = solution.GetRequiredDocument(documentId2); + + text1 = await document1.GetTextAsync(); + text2 = await document2.GetTextAsync(); + version1 = await document1.GetTextVersionAsync(); + version2 = await document2.GetTextVersionAsync(); + root1 = await document1.GetRequiredSyntaxRootAsync(CancellationToken.None); + root2 = await document2.GetRequiredSyntaxRootAsync(CancellationToken.None); + + Assert.NotEqual(text1.ToString(), text2.ToString()); + Assert.NotEqual(version1, version2); + + // We get different red and green nodes. + Assert.NotEqual(root1, root2); + Assert.False(root1.IsIncrementallyIdenticalTo(root2)); + + // Now apply the change to the workspace. This should bring the linked document in sync with the one we changed. + workspace.TryApplyChanges(solution); + solution = workspace.CurrentSolution; + + document1 = solution.GetRequiredDocument(documentId1); + document2 = solution.GetRequiredDocument(documentId2); + + text1 = await document1.GetTextAsync(); + text2 = await document2.GetTextAsync(); + version1 = await document1.GetTextVersionAsync(); + version2 = await document2.GetTextVersionAsync(); + root1 = await document1.GetRequiredSyntaxRootAsync(CancellationToken.None); + root2 = await document2.GetRequiredSyntaxRootAsync(CancellationToken.None); + + Assert.Equal(text1.ToString(), text2.ToString()); + Assert.Equal(version1, version2); + + // We get different red nodes, but they should be backed by the same green nodes. + Assert.NotEqual(root1, root2); + Assert.True(root1.IsIncrementallyIdenticalTo(root2)); + } + + private static Solution UpdateSolution(PreservationMode mode, TextUpdateType updateType, Solution solution, DocumentId documentId1, SourceText text, TextAndVersion textAndVersion) + { + solution = updateType switch + { + TextUpdateType.SourceText => solution.WithDocumentText(documentId1, text, mode), + TextUpdateType.TextAndVersion => solution.WithDocumentText(documentId1, textAndVersion, mode), + TextUpdateType.TextLoader => solution.WithDocumentTextLoader(documentId1, TextLoader.From(textAndVersion), mode), + _ => throw ExceptionUtilities.UnexpectedValue(updateType) + }; + return solution; + } + + [Theory, CombinatorialData] + public async Task WithDocumentText_LinkedFiles_PPConditionalDirective_SameParseOptions( + PreservationMode mode, + TextUpdateType updateType) + { + using var workspace = CreateWorkspaceWithProjectAndLinkedDocuments(""" + #if NETSTANDARD + public class Goo { } + """); + var solution = workspace.CurrentSolution; + + var documentId1 = solution.Projects.First().DocumentIds.Single(); + var documentId2 = solution.Projects.Last().DocumentIds.Single(); + + var document1 = solution.GetRequiredDocument(documentId1); + var document2 = solution.GetRequiredDocument(documentId2); + + var text1 = await document1.GetTextAsync(); + var text2 = await document2.GetTextAsync(); + var version1 = await document1.GetTextVersionAsync(); + var version2 = await document2.GetTextVersionAsync(); + var root1 = await document1.GetRequiredSyntaxRootAsync(CancellationToken.None); + var root2 = await document2.GetRequiredSyntaxRootAsync(CancellationToken.None); + + Assert.Equal(text1.ToString(), text2.ToString()); + Assert.Equal(version1, version2); + + // We can reuse trees with conditional directives if the parse options are the same. + Assert.NotEqual(root1, root2); + Assert.True(root1.IsIncrementallyIdenticalTo(root2)); + + var text = SourceText.From("new text", encoding: null, SourceHashAlgorithm.Sha1); + var textAndVersion = TextAndVersion.Create(text, VersionStamp.Create()); + solution = UpdateSolution(mode, updateType, solution, documentId1, text, textAndVersion); + + // because we only forked one doc, the text/versions should be different in this interim solution. + + document1 = solution.GetRequiredDocument(documentId1); + document2 = solution.GetRequiredDocument(documentId2); + + text1 = await document1.GetTextAsync(); + text2 = await document2.GetTextAsync(); + version1 = await document1.GetTextVersionAsync(); + version2 = await document2.GetTextVersionAsync(); + root1 = await document1.GetRequiredSyntaxRootAsync(CancellationToken.None); + root2 = await document2.GetRequiredSyntaxRootAsync(CancellationToken.None); + + Assert.NotEqual(text1.ToString(), text2.ToString()); + Assert.NotEqual(version1, version2); + + // We get different red and green nodes entirely + Assert.NotEqual(root1, root2); + Assert.False(root1.IsIncrementallyIdenticalTo(root2)); + + // Now apply the change to the workspace. This should bring the linked document in sync with the one we changed. + workspace.TryApplyChanges(solution); + solution = workspace.CurrentSolution; + + document1 = solution.GetRequiredDocument(documentId1); + document2 = solution.GetRequiredDocument(documentId2); + + text1 = await document1.GetTextAsync(); + text2 = await document2.GetTextAsync(); + version1 = await document1.GetTextVersionAsync(); + version2 = await document2.GetTextVersionAsync(); + root1 = await document1.GetRequiredSyntaxRootAsync(CancellationToken.None); + root2 = await document2.GetRequiredSyntaxRootAsync(CancellationToken.None); + + Assert.Equal(text1.ToString(), text2.ToString()); + Assert.Equal(version1, version2); + + // We can reuse trees with conditional directives if the parse options are the same. + Assert.NotEqual(root1, root2); + Assert.True(root1.IsIncrementallyIdenticalTo(root2)); + } + + [Theory, CombinatorialData] + public async Task WithDocumentText_LinkedFiles_PPConditionalDirective_DifferentParseOptions1( + PreservationMode mode, + TextUpdateType updateType) + { + var parseOptions1 = CSharpParseOptions.Default.WithPreprocessorSymbols("UNIQUE_NAME"); + var parseOptions2 = CSharpParseOptions.Default; + + using var workspace = CreateWorkspaceWithProjectAndLinkedDocuments(""" + #if NETSTANDARD + public class Goo { } + """, parseOptions1, parseOptions2); + var solution = workspace.CurrentSolution; + + var documentId1 = solution.Projects.First().DocumentIds.Single(); + var documentId2 = solution.Projects.Last().DocumentIds.Single(); + + var document1 = solution.GetRequiredDocument(documentId1); + var document2 = solution.GetRequiredDocument(documentId2); + + var text1 = await document1.GetTextAsync(); + var text2 = await document2.GetTextAsync(); + var version1 = await document1.GetTextVersionAsync(); + var version2 = await document2.GetTextVersionAsync(); + var root1 = await document1.GetRequiredSyntaxRootAsync(CancellationToken.None); + var root2 = await document2.GetRequiredSyntaxRootAsync(CancellationToken.None); + + Assert.Equal(text1.ToString(), text2.ToString()); + Assert.Equal(version1, version2); + + // We can never reuse trees with conditional directives. + Assert.NotEqual(root1, root2); + Assert.False(root1.IsIncrementallyIdenticalTo(root2)); + + Assert.Equal(parseOptions1, root1.SyntaxTree.Options); + Assert.Equal(parseOptions2, root2.SyntaxTree.Options); + + // Because we removed pp directives, we'll be able to reuse after this. + var text = SourceText.From("new text without pp directives", encoding: null, SourceHashAlgorithm.Sha1); + var textAndVersion = TextAndVersion.Create(text, VersionStamp.Create()); + solution = UpdateSolution(mode, updateType, solution, documentId1, text, textAndVersion); + + // because we only forked one doc, the text/versions should be different in this interim solution. + + document1 = solution.GetRequiredDocument(documentId1); + document2 = solution.GetRequiredDocument(documentId2); + + text1 = await document1.GetTextAsync(); + text2 = await document2.GetTextAsync(); + version1 = await document1.GetTextVersionAsync(); + version2 = await document2.GetTextVersionAsync(); + root1 = await document1.GetRequiredSyntaxRootAsync(CancellationToken.None); + root2 = await document2.GetRequiredSyntaxRootAsync(CancellationToken.None); + + Assert.NotEqual(text1.ToString(), text2.ToString()); + Assert.NotEqual(version1, version2); + + // We get different red and green nodes entirely + Assert.NotEqual(root1, root2); + Assert.False(root1.IsIncrementallyIdenticalTo(root2)); + + Assert.Equal(parseOptions1, root1.SyntaxTree.Options); + Assert.Equal(parseOptions2, root2.SyntaxTree.Options); + + // Now apply the change to the workspace. This should bring the linked document in sync with the one we changed. + workspace.TryApplyChanges(solution); + solution = workspace.CurrentSolution; + + document1 = solution.GetRequiredDocument(documentId1); + document2 = solution.GetRequiredDocument(documentId2); + + text1 = await document1.GetTextAsync(); + text2 = await document2.GetTextAsync(); + version1 = await document1.GetTextVersionAsync(); + version2 = await document2.GetTextVersionAsync(); + root1 = await document1.GetRequiredSyntaxRootAsync(CancellationToken.None); + root2 = await document2.GetRequiredSyntaxRootAsync(CancellationToken.None); + + Assert.Equal(text1.ToString(), text2.ToString()); + Assert.Equal(version1, version2); + + // We can reuse trees once they don't have conditional directives. + Assert.NotEqual(root1, root2); + Assert.True(root1.IsIncrementallyIdenticalTo(root2)); + + Assert.Equal(parseOptions1, root1.SyntaxTree.Options); + Assert.Equal(parseOptions2, root2.SyntaxTree.Options); + } + + [Theory, CombinatorialData] + public async Task WithDocumentText_LinkedFiles_PPConditionalDirective_DifferentParseOptions2( + PreservationMode mode, + TextUpdateType updateType) + { + using var workspace = CreateWorkspaceWithProjectAndLinkedDocuments(""" + #if NETSTANDARD + public class Goo { } + """, CSharpParseOptions.Default.WithPreprocessorSymbols("UNIQUE_NAME"), CSharpParseOptions.Default); + var solution = workspace.CurrentSolution; + + var documentId1 = solution.Projects.First().DocumentIds.Single(); + var documentId2 = solution.Projects.Last().DocumentIds.Single(); + + var document1 = solution.GetRequiredDocument(documentId1); + var document2 = solution.GetRequiredDocument(documentId2); + + var text1 = await document1.GetTextAsync(); + var text2 = await document2.GetTextAsync(); + var version1 = await document1.GetTextVersionAsync(); + var version2 = await document2.GetTextVersionAsync(); + var root1 = await document1.GetRequiredSyntaxRootAsync(CancellationToken.None); + var root2 = await document2.GetRequiredSyntaxRootAsync(CancellationToken.None); + + Assert.Equal(text1.ToString(), text2.ToString()); + Assert.Equal(version1, version2); + + // We can never reuse trees with conditional directives. + Assert.NotEqual(root1, root2); + Assert.False(root1.IsIncrementallyIdenticalTo(root2)); + + // Because we still have pp directives, we'll still not be able to reuse the file. + var text = SourceText.From("#if true", encoding: null, SourceHashAlgorithm.Sha1); + var textAndVersion = TextAndVersion.Create(text, VersionStamp.Create()); + solution = UpdateSolution(mode, updateType, solution, documentId1, text, textAndVersion); + + // because we only forked one doc, the text/versions should be different in this interim solution. + + document1 = solution.GetRequiredDocument(documentId1); + document2 = solution.GetRequiredDocument(documentId2); + + text1 = await document1.GetTextAsync(); + text2 = await document2.GetTextAsync(); + version1 = await document1.GetTextVersionAsync(); + version2 = await document2.GetTextVersionAsync(); + root1 = await document1.GetRequiredSyntaxRootAsync(CancellationToken.None); + root2 = await document2.GetRequiredSyntaxRootAsync(CancellationToken.None); + + Assert.NotEqual(text1.ToString(), text2.ToString()); + Assert.NotEqual(version1, version2); + + // We get different red and green nodes entirely + Assert.NotEqual(root1, root2); + Assert.False(root1.IsIncrementallyIdenticalTo(root2)); + + // Now apply the change to the workspace. This should bring the linked document in sync with the one we changed. + workspace.TryApplyChanges(solution); + solution = workspace.CurrentSolution; + + document1 = solution.GetRequiredDocument(documentId1); + document2 = solution.GetRequiredDocument(documentId2); + + text1 = await document1.GetTextAsync(); + text2 = await document2.GetTextAsync(); + version1 = await document1.GetTextVersionAsync(); + version2 = await document2.GetTextVersionAsync(); + root1 = await document1.GetRequiredSyntaxRootAsync(CancellationToken.None); + root2 = await document2.GetRequiredSyntaxRootAsync(CancellationToken.None); + + Assert.Equal(text1.ToString(), text2.ToString()); + Assert.Equal(version1, version2); + + // We can never reuse trees with conditional directives. + Assert.NotEqual(root1, root2); + Assert.False(root1.IsIncrementallyIdenticalTo(root2)); + } + + [Theory, CombinatorialData] + public async Task WithDocumentText_LinkedFiles_NonConditionalDirective( + PreservationMode mode, + TextUpdateType updateType) + { + using var workspace = CreateWorkspaceWithProjectAndLinkedDocuments(""" + #nullable enable // should not impact being able to reuse. + public class Goo { } + """); + var solution = workspace.CurrentSolution; + + var documentId1 = solution.Projects.First().DocumentIds.Single(); + var documentId2 = solution.Projects.Last().DocumentIds.Single(); + + var document1 = solution.GetRequiredDocument(documentId1); + var document2 = solution.GetRequiredDocument(documentId2); + + var text1 = await document1.GetTextAsync(); + var text2 = await document2.GetTextAsync(); + var version1 = await document1.GetTextVersionAsync(); + var version2 = await document2.GetTextVersionAsync(); + var root1 = await document1.GetRequiredSyntaxRootAsync(CancellationToken.None); + var root2 = await document2.GetRequiredSyntaxRootAsync(CancellationToken.None); + + Assert.Equal(text1.ToString(), text2.ToString()); + Assert.Equal(version1, version2); + + // We get different red nodes, but they should be backed by the same green nodes. + Assert.NotEqual(root1, root2); + Assert.True(root1.IsIncrementallyIdenticalTo(root2)); + + var text = SourceText.From("new text", encoding: null, SourceHashAlgorithm.Sha1); + var textAndVersion = TextAndVersion.Create(text, VersionStamp.Create()); + solution = UpdateSolution(mode, updateType, solution, documentId1, text, textAndVersion); + + // because we only forked one doc, the text/versions should be different in this interim solution. + + document1 = solution.GetRequiredDocument(documentId1); + document2 = solution.GetRequiredDocument(documentId2); + + text1 = await document1.GetTextAsync(); + text2 = await document2.GetTextAsync(); + version1 = await document1.GetTextVersionAsync(); + version2 = await document2.GetTextVersionAsync(); + root1 = await document1.GetRequiredSyntaxRootAsync(CancellationToken.None); + root2 = await document2.GetRequiredSyntaxRootAsync(CancellationToken.None); + + Assert.NotEqual(text1.ToString(), text2.ToString()); + Assert.NotEqual(version1, version2); + + // We get different red and green nodes. + Assert.NotEqual(root1, root2); + Assert.False(root1.IsIncrementallyIdenticalTo(root2)); + + // Now apply the change to the workspace. This should bring the linked document in sync with the one we changed. + workspace.TryApplyChanges(solution); + solution = workspace.CurrentSolution; + + document1 = solution.GetRequiredDocument(documentId1); + document2 = solution.GetRequiredDocument(documentId2); + + text1 = await document1.GetTextAsync(); + text2 = await document2.GetTextAsync(); + version1 = await document1.GetTextVersionAsync(); + version2 = await document2.GetTextVersionAsync(); + root1 = await document1.GetRequiredSyntaxRootAsync(CancellationToken.None); + root2 = await document2.GetRequiredSyntaxRootAsync(CancellationToken.None); + + Assert.Equal(text1.ToString(), text2.ToString()); + Assert.Equal(version1, version2); + + // We get different red nodes, but they should be backed by the same green nodes. + Assert.NotEqual(root1, root2); + Assert.True(root1.IsIncrementallyIdenticalTo(root2)); + } + [Fact] public void WithAdditionalDocumentText_SourceText() { @@ -3780,7 +4216,7 @@ public void TestOptionChangesForLanguagesNotInSolution() // Create an empty solution with no projects. using var workspace = CreateWorkspace(); var s0 = workspace.CurrentSolution; - var optionService = workspace.Services.GetRequiredService(); + var optionService = workspace.Services.GetRequiredService().LegacyGlobalOptions; // Apply an option change to a C# option. var option = FormattingOptions.UseTabs; @@ -3917,7 +4353,7 @@ public async Task EditorConfigOptions(string projectPath, string configPath, str #pragma warning disable RS0030 // Do not used banned APIs var documentOptions = await document.GetOptionsAsync(CancellationToken.None); - Assert.Equal(appliedToDocument, documentOptions.GetOption(FormattingOptions2.UseTabs)); + Assert.Equal(appliedToDocument, documentOptions.GetOption(FormattingOptions.UseTabs)); #pragma warning restore var syntaxTree = await document.GetSyntaxTreeAsync(); diff --git a/src/Workspaces/CoreTest/WorkspaceServiceTests/GlobalOptionServiceTests.cs b/src/Workspaces/CoreTest/WorkspaceServiceTests/GlobalOptionServiceTests.cs index 4a6fdbf09d6de..7ba8ea0566bdc 100644 --- a/src/Workspaces/CoreTest/WorkspaceServiceTests/GlobalOptionServiceTests.cs +++ b/src/Workspaces/CoreTest/WorkspaceServiceTests/GlobalOptionServiceTests.cs @@ -5,17 +5,11 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.IO; using System.Linq; -using System.Threading; -using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeStyle; -using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Options.Providers; -using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Roslyn.Utilities; @@ -27,77 +21,132 @@ namespace Microsoft.CodeAnalysis.UnitTests.WorkspaceServices [Trait(Traits.Feature, Traits.Features.Workspace)] public class GlobalOptionServiceTests { - private static IGlobalOptionService GetGlobalOptionService(HostWorkspaceServices services, IOptionPersisterProvider? optionPersisterProvider = null) - { - var mefHostServices = services.SolutionServices.ExportProvider; - var workspaceThreadingService = mefHostServices.GetExportedValues().SingleOrDefault(); - return new GlobalOptionService( - workspaceThreadingService, - new[] - { - new Lazy(() => optionPersisterProvider ??= new TestOptionsPersisterProvider()) - }); - } + private static IGlobalOptionService GetGlobalOptionService(HostWorkspaceServices services) + => services.SolutionServices.ExportProvider.GetExportedValue(); - private static ILegacyWorkspaceOptionService GetOptionService(HostWorkspaceServices services, IOptionPersisterProvider? optionPersisterProvider = null) - => new TestService(GetGlobalOptionService(services, optionPersisterProvider)); + private static ILegacyGlobalOptionService GetLegacyGlobalOptionService(HostWorkspaceServices services) + => services.SolutionServices.ExportProvider.GetExportedValue(); - private sealed class TestService : ILegacyWorkspaceOptionService + [Fact] + public void LegacyGlobalOptions_SetGet() { - public IGlobalOptionService GlobalOptions { get; } + using var workspace = new AdhocWorkspace(); + var optionService = GetLegacyGlobalOptionService(workspace.Services); - public TestService(IGlobalOptionService globalOptions) - => GlobalOptions = globalOptions; + var optionKey = new OptionKey(new TestOption() { DefaultValue = 1 }); - public object? GetOption(OptionKey key) - => GlobalOptions.GetOption(key); + Assert.Equal(1, optionService.GetExternallyDefinedOption(optionKey)); - public void SetOptions(OptionSet optionSet, IEnumerable optionKeys) - => GlobalOptions.SetOptions(optionSet, optionKeys); + optionService.SetOptions( + ImmutableArray>.Empty, + ImmutableArray.Create(KeyValuePairUtil.Create(optionKey, (object?)2))); - public void RegisterWorkspace(Workspace workspace) - => throw new NotImplementedException(); + Assert.Equal(2, optionService.GetExternallyDefinedOption(optionKey)); - public void UnregisterWorkspace(Workspace workspace) - => throw new NotImplementedException(); - } + optionService.SetOptions( + ImmutableArray>.Empty, + ImmutableArray.Create(KeyValuePairUtil.Create(optionKey, (object?)3))); - internal class TestOptionsProvider : IOptionProvider - { - public ImmutableArray Options { get; } = ImmutableArray.Create( - new Option("Test Feature", "Test Name", false)); + Assert.Equal(3, optionService.GetExternallyDefinedOption(optionKey)); } - internal sealed class TestOptionsPersisterProvider : IOptionPersisterProvider + [Theory] + [CombinatorialData] + public void ExternallyDefinedOption(bool subclass) { - private readonly ValueTask _optionPersisterTask; + using var workspace1 = new AdhocWorkspace(); + using var workspace2 = new AdhocWorkspace(); + var optionService = GetLegacyGlobalOptionService(workspace1.Services); + var optionSet = new SolutionOptionSet(optionService); + + var option = subclass ? (IOption)new TestOption(defaultValue: 1) : new TestOption() { DefaultValue = 1 }; + var perLanguageOption = subclass ? (IOption)new PerLanguageTestOption(defaultValue: 1) : new TestOption() { IsPerLanguage = true, DefaultValue = 1 }; + + var optionKey = new OptionKey(option); + var perLanguageOptionKey = new OptionKey(perLanguageOption, "lang"); - public TestOptionsPersisterProvider(IOptionPersister? optionPersister = null) - => _optionPersisterTask = new(optionPersister ?? new TestOptionsPersister()); + Assert.Equal(optionKey.Option.DefaultValue, optionSet.GetOption(optionKey)); + Assert.Equal(perLanguageOptionKey.Option.DefaultValue, optionSet.GetOption(perLanguageOptionKey)); - public ValueTask GetOrCreatePersisterAsync(CancellationToken cancellationToken) - => _optionPersisterTask; + var newSet = optionSet.WithChangedOption(optionKey, 2).WithChangedOption(perLanguageOptionKey, 3); + Assert.Equal(2, newSet.GetOption(optionKey)); + Assert.Equal(3, newSet.GetOption(perLanguageOptionKey)); + + var newSolution1 = workspace1.CurrentSolution.WithOptions(newSet); + Assert.Equal(2, newSolution1.Options.GetOption(optionKey)); + Assert.Equal(3, newSolution1.Options.GetOption(perLanguageOptionKey)); + + // TryApplyChanges propagates the option to all workspaces: + var oldSolution2 = workspace2.CurrentSolution; + Assert.Equal(1, oldSolution2.Options.GetOption(optionKey)); + Assert.Equal(1, oldSolution2.Options.GetOption(perLanguageOptionKey)); + + Assert.True(workspace1.TryApplyChanges(newSolution1)); + + var newSolution2 = workspace2.CurrentSolution; + Assert.Equal(2, newSolution2.Options.GetOption(optionKey)); + Assert.Equal(3, newSolution2.Options.GetOption(perLanguageOptionKey)); } - internal sealed class TestOptionsPersister : IOptionPersister + [Fact] + public void InternallyDefinedOption() { - private ImmutableDictionary _options = ImmutableDictionary.Empty; + using var workspace1 = new AdhocWorkspace(); + using var workspace2 = new AdhocWorkspace(); + var optionService = GetLegacyGlobalOptionService(workspace1.Services); + var optionSet = new SolutionOptionSet(optionService); - public bool TryFetch(OptionKey optionKey, out object? value) - => _options.TryGetValue(optionKey, out value); + var perLanguageOptionKey = new OptionKey(FormattingOptions.NewLine, "lang"); - public bool TryPersist(OptionKey optionKey, object? value) - { - _options = _options.SetItem(optionKey, value); - return true; - } + Assert.Equal(perLanguageOptionKey.Option.DefaultValue, optionSet.GetOption(perLanguageOptionKey)); + + var newSet = optionSet.WithChangedOption(perLanguageOptionKey, "EOLN"); + Assert.Equal("EOLN", newSet.GetOption(perLanguageOptionKey)); + + var newSolution1 = workspace1.CurrentSolution.WithOptions(newSet); + Assert.Equal("EOLN", newSolution1.Options.GetOption(perLanguageOptionKey)); + + // TryApplyChanges propagates the option to all workspaces: + var oldSolution2 = workspace2.CurrentSolution; + Assert.Equal(perLanguageOptionKey.Option.DefaultValue, oldSolution2.Options.GetOption(perLanguageOptionKey)); + + Assert.True(workspace1.TryApplyChanges(newSolution1)); + + Assert.Equal("EOLN", workspace1.CurrentSolution.Options.GetOption(perLanguageOptionKey)); + Assert.Equal("EOLN", workspace2.CurrentSolution.Options.GetOption(perLanguageOptionKey)); + + // Update global option directly (after the value is cached in the above current solution snapshots). + // Doing so does NOT update current solutions. + optionService.GlobalOptions.SetGlobalOption(FormattingOptions2.NewLine, "lang", "NEW_LINE"); + + Assert.Equal("EOLN", workspace1.CurrentSolution.Options.GetOption(perLanguageOptionKey)); + Assert.Equal("EOLN", workspace2.CurrentSolution.Options.GetOption(perLanguageOptionKey)); + + // Update global option indirectly via legacy service updates current solutions. + optionService.SetOptions( + ImmutableArray.Create(KeyValuePairUtil.Create(new OptionKey2(FormattingOptions2.NewLine, "lang"), (object?)"NEW_LINE")), + ImmutableArray>.Empty); + + Assert.Equal("NEW_LINE", workspace1.CurrentSolution.Options.GetOption(perLanguageOptionKey)); + Assert.Equal("NEW_LINE", workspace2.CurrentSolution.Options.GetOption(perLanguageOptionKey)); + + // Set the option directly again and trigger workspace update: + optionService.GlobalOptions.SetGlobalOption(FormattingOptions2.NewLine, "lang", "NEW_LINE2"); + + Assert.Equal("NEW_LINE", workspace1.CurrentSolution.Options.GetOption(perLanguageOptionKey)); + Assert.Equal("NEW_LINE", workspace2.CurrentSolution.Options.GetOption(perLanguageOptionKey)); + + optionService.UpdateRegisteredWorkspaces(); + + Assert.Equal("NEW_LINE2", workspace1.CurrentSolution.Options.GetOption(perLanguageOptionKey)); + Assert.Equal("NEW_LINE2", workspace2.CurrentSolution.Options.GetOption(perLanguageOptionKey)); } [Fact] public void OptionPerLanguageOption() { using var workspace = new AdhocWorkspace(); - var optionService = GetOptionService(workspace.Services); + var optionService = GetLegacyGlobalOptionService(workspace.Services); var optionSet = new SolutionOptionSet(optionService); var optionvalid = new PerLanguageOption("Test Feature", "Test Name", false); @@ -108,7 +157,7 @@ public void OptionPerLanguageOption() public void GettingOptionReturnsOption() { using var workspace = new AdhocWorkspace(); - var optionService = GetOptionService(workspace.Services); + var optionService = GetLegacyGlobalOptionService(workspace.Services); var optionSet = new SolutionOptionSet(optionService); var option = new Option("Test Feature", "Test Name", false); Assert.False(optionSet.GetOption(option)); @@ -119,30 +168,31 @@ public void GlobalOptions() { using var workspace = new AdhocWorkspace(); var globalOptions = GetGlobalOptionService(workspace.Services); - var option1 = new Option2("Feature1", "Name1", defaultValue: 1); - var option2 = new Option2("Feature2", "Name2", defaultValue: 2); - var option3 = new Option2("Feature3", "Name3", defaultValue: 3); + var option1 = new Option2("test_option1", defaultValue: 1); + var option2 = new Option2("test_option2", defaultValue: 2); + var option3 = new Option2("test_option3", defaultValue: 3); var changedOptions = new List(); var handler = new EventHandler((_, e) => changedOptions.Add(e)); globalOptions.OptionChanged += handler; - var values = globalOptions.GetOptions(ImmutableArray.Create(new OptionKey(option1), new OptionKey(option2))); + var values = globalOptions.GetOptions(ImmutableArray.Create(new OptionKey2(option1), new OptionKey2(option2))); Assert.Equal(1, values[0]); Assert.Equal(2, values[1]); - globalOptions.SetGlobalOptions( - ImmutableArray.Create(new OptionKey(option1), new OptionKey(option2), new OptionKey(option3)), - ImmutableArray.Create(5, 6, 3)); + globalOptions.SetGlobalOptions(ImmutableArray.Create( + KeyValuePairUtil.Create(new OptionKey2(option1), (object?)5), + KeyValuePairUtil.Create(new OptionKey2(option2), (object?)6), + KeyValuePairUtil.Create(new OptionKey2(option3), (object?)3))); AssertEx.Equal(new[] { - "Name1=5", - "Name2=6", - }, changedOptions.Select(e => $"{e.OptionKey.Option.Name}={e.Value}")); + "test_option1=5", + "test_option2=6", + }, changedOptions.Select(e => $"{e.Option.Definition.ConfigName}={e.Value}")); - values = globalOptions.GetOptions(ImmutableArray.Create(new OptionKey(option1), new OptionKey(option2), new OptionKey(option3))); + values = globalOptions.GetOptions(ImmutableArray.Create(new OptionKey2(option1), new OptionKey2(option2), new OptionKey2(option3))); Assert.Equal(5, values[0]); Assert.Equal(6, values[1]); Assert.Equal(3, values[2]); @@ -158,7 +208,7 @@ public void GlobalOptions() public void GettingOptionWithChangedOption() { using var workspace = new AdhocWorkspace(); - var optionService = GetOptionService(workspace.Services); + var optionService = GetLegacyGlobalOptionService(workspace.Services); OptionSet optionSet = new SolutionOptionSet(optionService); var option = new Option("Test Feature", "Test Name", false); var key = new OptionKey(option); @@ -171,8 +221,7 @@ public void GettingOptionWithChangedOption() public void GettingOptionWithoutChangedOption() { using var workspace = new AdhocWorkspace(); - var optionService = GetOptionService(workspace.Services); - var optionSet = new SolutionOptionSet(optionService); + var optionSet = new SolutionOptionSet(GetLegacyGlobalOptionService(workspace.Services)); var optionFalse = new Option("Test Feature", "Test Name", false); Assert.False(optionSet.GetOption(optionFalse)); @@ -187,44 +236,18 @@ public void GettingOptionWithoutChangedOption() Assert.True((bool?)optionSet.GetOption(trueKey)); } - [Fact] - public void GetKnownOptions() - { - using var workspace = new AdhocWorkspace(); - var optionService = GetOptionService(workspace.Services); - var option = new Option("Test Feature", "Test Name", defaultValue: true); - optionService.GetOption(option); - - var optionSet = new SolutionOptionSet(optionService); - var value = optionSet.GetOption(option); - Assert.True(value); - } - - [Fact] - public void GetKnownOptionsKey() - { - using var workspace = new AdhocWorkspace(); - var optionService = GetOptionService(workspace.Services); - var option = new Option("Test Feature", "Test Name", defaultValue: true); - optionService.GetOption(option); - - var optionSet = new SolutionOptionSet(optionService); - var optionKey = new OptionKey(option); - var value = (bool?)optionSet.GetOption(optionKey); - Assert.True(value); - } - [Fact] public void SetKnownOptions() { using var workspace = new AdhocWorkspace(); - var optionService = GetOptionService(workspace.Services); + var optionService = GetLegacyGlobalOptionService(workspace.Services); var optionSet = new SolutionOptionSet(optionService); var option = new Option("Test Feature", "Test Name", defaultValue: true); var optionKey = new OptionKey(option); var newOptionSet = optionSet.WithChangedOption(optionKey, false); - optionService.GlobalOptions.SetOptions(newOptionSet, ((SolutionOptionSet)newOptionSet).GetChangedOptions()); + var changedOptions = ((SolutionOptionSet)newOptionSet).GetChangedOptions(); + optionService.SetOptions(changedOptions.internallyDefined, changedOptions.externallyDefined); var isOptionSet = (bool?)new SolutionOptionSet(optionService).GetOption(optionKey); Assert.False(isOptionSet); } @@ -233,7 +256,7 @@ public void SetKnownOptions() public void OptionSetIsImmutable() { using var workspace = new AdhocWorkspace(); - var optionService = GetOptionService(workspace.Services); + var optionService = GetLegacyGlobalOptionService(workspace.Services); var optionSet = new SolutionOptionSet(optionService); var option = new Option("Test Feature", "Test Name", defaultValue: true); @@ -247,148 +270,54 @@ public void OptionSetIsImmutable() public void TestPerLanguageCodeStyleOptions() { using var workspace = new AdhocWorkspace(); - var perLanguageOption2 = new PerLanguageOption2>("test", "test", new CodeStyleOption2(false, NotificationOption2.Warning)); + var perLanguageOption2 = new PerLanguageOption2>("test", new CodeStyleOption2(false, NotificationOption2.Warning)).WithPublicOption("test", "test"); var perLanguageOption = perLanguageOption2.ToPublicOption(); var newValueCodeStyleOption2 = new CodeStyleOption2(!perLanguageOption2.DefaultValue.Value, perLanguageOption2.DefaultValue.Notification); var newValueCodeStyleOption = (CodeStyleOption)newValueCodeStyleOption2!; - // Test "OptionKey" based overloads for get/set options on OptionSet and OptionService using different public and internal type combinations. + TestPublicOption(workspace, perLanguageOption, language: LanguageNames.CSharp, newValueCodeStyleOption); + TestInternalOption(workspace, perLanguageOption2, language: LanguageNames.CSharp, newValueCodeStyleOption2); - // 1. { PerLanguageOption, CodeStyleOption } - TestCodeStyleOptionsCommon(workspace, perLanguageOption, LanguageNames.CSharp, newValueCodeStyleOption); - - // 2. { PerLanguageOption2, CodeStyleOption } - TestCodeStyleOptionsCommon(workspace, perLanguageOption2, LanguageNames.CSharp, newValueCodeStyleOption); - - // 3. { PerLanguageOption, CodeStyleOption2 } - TestCodeStyleOptionsCommon(workspace, perLanguageOption, LanguageNames.CSharp, newValueCodeStyleOption2); - - // 4. { PerLanguageOption2, CodeStyleOption2 } - TestCodeStyleOptionsCommon(workspace, perLanguageOption2, LanguageNames.CSharp, newValueCodeStyleOption2); - - var optionService = GetOptionService(workspace.Services); + var optionService = GetLegacyGlobalOptionService(workspace.Services); var originalOptionSet = new SolutionOptionSet(optionService); - - // Test "PerLanguageOption" and "PerLanguageOption2" overloads for OptionSet and OptionService. - - // 1. Verify default value. - Assert.Equal(perLanguageOption.DefaultValue, originalOptionSet.GetOption(perLanguageOption, LanguageNames.CSharp)); - Assert.Equal(perLanguageOption2.DefaultValue, originalOptionSet.GetOption(perLanguageOption2, LanguageNames.CSharp)); - - // 2. OptionSet validations. - var newOptionSet = originalOptionSet.WithChangedOption(perLanguageOption, LanguageNames.CSharp, newValueCodeStyleOption); - Assert.Equal(newValueCodeStyleOption, newOptionSet.GetOption(perLanguageOption, LanguageNames.CSharp)); - Assert.Equal(newValueCodeStyleOption2, newOptionSet.GetOption(perLanguageOption2, LanguageNames.CSharp)); - - newOptionSet = originalOptionSet.WithChangedOption(perLanguageOption2, LanguageNames.CSharp, newValueCodeStyleOption2); - Assert.Equal(newValueCodeStyleOption, newOptionSet.GetOption(perLanguageOption, LanguageNames.CSharp)); - Assert.Equal(newValueCodeStyleOption2, newOptionSet.GetOption(perLanguageOption2, LanguageNames.CSharp)); - - // 3. IOptionService validation - - optionService.GlobalOptions.SetOptions(newOptionSet, ((SolutionOptionSet)newOptionSet).GetChangedOptions()); - Assert.Equal(newValueCodeStyleOption2, optionService.GlobalOptions.GetOption(perLanguageOption2, LanguageNames.CSharp)); } [Fact] public void TestLanguageSpecificCodeStyleOptions() { using var workspace = new AdhocWorkspace(); - var option2 = new Option2>("test", "test", new CodeStyleOption2(false, NotificationOption2.Warning)); + var option2 = new Option2>("test", new CodeStyleOption2(false, NotificationOption2.Warning)).WithPublicOption("test", "test"); var option = option2.ToPublicOption(); var newValueCodeStyleOption2 = new CodeStyleOption2(!option2.DefaultValue.Value, option2.DefaultValue.Notification); var newValueCodeStyleOption = (CodeStyleOption)newValueCodeStyleOption2!; - // Test "OptionKey" based overloads for get/set options on OptionSet and OptionService using different public and internal type combinations. - - // 1. { Option, CodeStyleOption } - TestCodeStyleOptionsCommon(workspace, option, language: null, newValueCodeStyleOption); - - // 2. { Option2, CodeStyleOption } - TestCodeStyleOptionsCommon(workspace, option2, language: null, newValueCodeStyleOption); - - // 3. { Option, CodeStyleOption2 } - TestCodeStyleOptionsCommon(workspace, option, language: null, newValueCodeStyleOption2); - - // 4. { Option2, CodeStyleOption2 } - TestCodeStyleOptionsCommon(workspace, option2, language: null, newValueCodeStyleOption2); - - var optionService = GetOptionService(workspace.Services); - var originalOptionSet = new SolutionOptionSet(optionService); - - // Test "Option" and "Option2" overloads for OptionSet and OptionService. - - // 1. Verify default value. - Assert.Equal(option.DefaultValue, originalOptionSet.GetOption(option)); - Assert.Equal(option2.DefaultValue, originalOptionSet.GetOption(option2)); - - // 2. OptionSet validations. - var newOptionSet = originalOptionSet.WithChangedOption(option, newValueCodeStyleOption); - Assert.Equal(newValueCodeStyleOption, newOptionSet.GetOption(option)); - Assert.Equal(newValueCodeStyleOption2, newOptionSet.GetOption(option2)); - - newOptionSet = originalOptionSet.WithChangedOption(option2, newValueCodeStyleOption2); - Assert.Equal(newValueCodeStyleOption, newOptionSet.GetOption(option)); - Assert.Equal(newValueCodeStyleOption2, newOptionSet.GetOption(option2)); - - // 3. IOptionService validation - optionService.GlobalOptions.SetOptions(newOptionSet, ((SolutionOptionSet)newOptionSet).GetChangedOptions()); - Assert.Equal(newValueCodeStyleOption2, optionService.GlobalOptions.GetOption(option2)); + TestPublicOption(workspace, option, language: null, newValueCodeStyleOption); + TestInternalOption(workspace, option2, language: null, newValueCodeStyleOption2); } - private static void TestCodeStyleOptionsCommon(Workspace workspace, IOption2 option, string? language, TCodeStyleOption newValue) - where TCodeStyleOption : ICodeStyleOption + private static void TestPublicOption(Workspace workspace, IPublicOption option, string? language, CodeStyleOption newPublicValue) { - var optionService = GetOptionService(workspace.Services); + var optionService = GetLegacyGlobalOptionService(workspace.Services); var originalOptionSet = new SolutionOptionSet(optionService); - // Test matrix using different OptionKey and OptionKey2 get/set operations. var optionKey = new OptionKey(option, language); - var optionKey2 = option switch - { - IPerLanguageValuedOption perLanguageValuedOption => new OptionKey2(perLanguageValuedOption, language!), - ISingleValuedOption singleValued => new OptionKey2(singleValued), - _ => throw ExceptionUtilities.Unreachable(), - }; - - // Value return from "object GetOption(OptionKey)" should always be public CodeStyleOption type. - var newPublicValue = newValue.AsPublicCodeStyleOption(); // 1. WithChangedOption(OptionKey), GetOption(OptionKey)/GetOption(OptionKey) - var newOptionSet = originalOptionSet.WithChangedOption(optionKey, newValue); + var newOptionSet = originalOptionSet.WithChangedOption(optionKey, newPublicValue); Assert.Equal(newPublicValue, newOptionSet.GetOption(optionKey)); - // Value returned from public API should always be castable to public CodeStyleOption type. - Assert.NotNull((CodeStyleOption)newOptionSet.GetOption(optionKey)!); - // Verify "T GetOption(OptionKey)" works for both cases of T being a public and internal code style option type. + Assert.IsType>(newOptionSet.GetOption(optionKey)); + + // Verify "T GetOption(OptionKey)" works for T being a public code style option type. Assert.Equal(newPublicValue, newOptionSet.GetOption>(optionKey)); - Assert.Equal(newValue, newOptionSet.GetOption(optionKey)); + } - // 2. WithChangedOption(OptionKey), GetOption(OptionKey2)/GetOption(OptionKey2) - newOptionSet = originalOptionSet.WithChangedOption(optionKey, newValue); - Assert.Equal(newPublicValue, newOptionSet.GetOption(optionKey2)); - // Verify "T GetOption(OptionKey2)" works for both cases of T being a public and internal code style option type. - Assert.Equal(newPublicValue, newOptionSet.GetOption>(optionKey2)); - Assert.Equal(newValue, newOptionSet.GetOption(optionKey2)); + private static void TestInternalOption(Workspace workspace, IOption2 option, string? language, CodeStyleOption2 newValue) + { + var optionService = GetLegacyGlobalOptionService(workspace.Services); + var optionKey = new OptionKey2(option, language); - // 3. WithChangedOption(OptionKey2), GetOption(OptionKey)/GetOption(OptionKey) - newOptionSet = originalOptionSet.WithChangedOption(optionKey2, newValue); - Assert.Equal(newPublicValue, newOptionSet.GetOption(optionKey)); - // Value returned from public API should always be castable to public CodeStyleOption type. - Assert.NotNull((CodeStyleOption)newOptionSet.GetOption(optionKey)!); - // Verify "T GetOption(OptionKey)" works for both cases of T being a public and internal code style option type. - Assert.Equal(newPublicValue, newOptionSet.GetOption>(optionKey)); - Assert.Equal(newValue, newOptionSet.GetOption(optionKey)); - - // 4. WithChangedOption(OptionKey2), GetOption(OptionKey2)/GetOption(OptionKey2) - newOptionSet = originalOptionSet.WithChangedOption(optionKey2, newValue); - Assert.Equal(newPublicValue, newOptionSet.GetOption(optionKey2)); - // Verify "T GetOption(OptionKey2)" works for both cases of T being a public and internal code style option type. - Assert.Equal(newPublicValue, newOptionSet.GetOption>(optionKey2)); - Assert.Equal(newValue, newOptionSet.GetOption(optionKey2)); - - // 5. IOptionService.GetOption(OptionKey) - optionService.GlobalOptions.SetOptions(newOptionSet, ((SolutionOptionSet)newOptionSet).GetChangedOptions()); - Assert.Equal(newPublicValue, optionService.GetOption(optionKey)); + optionService.SetOptions(ImmutableArray.Create(new KeyValuePair(optionKey, newValue)), ImmutableArray>.Empty); + Assert.Equal(newValue, optionService.GlobalOptions.GetOption>(optionKey)); } } } diff --git a/src/Workspaces/CoreTestUtilities/Fakes/TestOptionSet.cs b/src/Workspaces/CoreTestUtilities/Fakes/TestOptionSet.cs index 890895f8eda87..fb4a1833cd3a6 100644 --- a/src/Workspaces/CoreTestUtilities/Fakes/TestOptionSet.cs +++ b/src/Workspaces/CoreTestUtilities/Fakes/TestOptionSet.cs @@ -2,47 +2,32 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics; +using System.Linq; using Microsoft.CodeAnalysis.Options; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Test.Utilities { internal class TestOptionSet : OptionSet { - private readonly ImmutableDictionary _values; + public static new readonly TestOptionSet Empty = new(ImmutableDictionary.Empty); - public TestOptionSet() - { - _values = ImmutableDictionary.Empty; - } + private readonly ImmutableDictionary _values; - private TestOptionSet(ImmutableDictionary values) + public TestOptionSet(ImmutableDictionary values) { + Debug.Assert(values.Values.All(IsInternalOptionValue)); _values = values; } - private protected override object? GetOptionCore(OptionKey optionKey) - { - Contract.ThrowIfFalse(_values.TryGetValue(optionKey, out var value)); - - return value; - } - - public override OptionSet WithChangedOption(OptionKey optionAndLanguage, object? value) - { - return new TestOptionSet(_values.SetItem(optionAndLanguage, value)); - } + internal override object? GetInternalOptionValue(OptionKey optionKey) + => _values.TryGetValue(optionKey, out var value) ? value : optionKey.Option.DefaultValue; - internal override IEnumerable GetChangedOptions(OptionSet optionSet) + internal override OptionSet WithChangedOptionInternal(OptionKey optionKey, object? internalValue) { - foreach (var (key, value) in _values) - { - var currentValue = optionSet.GetOption(key); - if (!object.Equals(currentValue, value)) - yield return key; - } + Debug.Assert(IsInternalOptionValue(internalValue)); + return new TestOptionSet(_values.SetItem(optionKey, internalValue)); } } } diff --git a/src/Workspaces/CoreTestUtilities/Formatting/FormattingTestBase.cs b/src/Workspaces/CoreTestUtilities/Formatting/FormattingTestBase.cs index 3573c94ad1a9e..3751a2c995f9e 100644 --- a/src/Workspaces/CoreTestUtilities/Formatting/FormattingTestBase.cs +++ b/src/Workspaces/CoreTestUtilities/Formatting/FormattingTestBase.cs @@ -39,7 +39,7 @@ private protected async Task AssertFormatAsync( #pragma warning disable IDE0060 // Remove unused parameter - https://github.com/dotnet/roslyn/issues/44225 bool debugMode = false, #pragma warning restore IDE0060 // Remove unused parameter - OptionsCollection? changedOptionSet = null, + OptionsCollection? changedOptions = null, bool treeCompare = true, ParseOptions? parseOptions = null) { @@ -54,8 +54,8 @@ private protected async Task AssertFormatAsync( var document = project.AddDocument("Document", SourceText.From(code)); var formattingService = document.GetRequiredLanguageService(); - var formattingOptions = changedOptionSet != null - ? formattingService.GetFormattingOptions(changedOptionSet.ToAnalyzerConfigOptions(document.Project.Services), fallbackOptions: null) + var formattingOptions = changedOptions != null + ? formattingService.GetFormattingOptions(changedOptions, fallbackOptions: null) : formattingService.DefaultOptions; var syntaxTree = await document.GetRequiredSyntaxTreeAsync(CancellationToken.None); diff --git a/src/Workspaces/CoreTestUtilities/Microsoft.CodeAnalysis.Workspaces.Test.Utilities.csproj b/src/Workspaces/CoreTestUtilities/Microsoft.CodeAnalysis.Workspaces.Test.Utilities.csproj index c9d1803318502..0eab42b807afb 100644 --- a/src/Workspaces/CoreTestUtilities/Microsoft.CodeAnalysis.Workspaces.Test.Utilities.csproj +++ b/src/Workspaces/CoreTestUtilities/Microsoft.CodeAnalysis.Workspaces.Test.Utilities.csproj @@ -53,5 +53,6 @@ + diff --git a/src/Workspaces/CoreTest/Options/OptionsTestHelpers.cs b/src/Workspaces/CoreTestUtilities/Options/OptionsTestHelpers.cs similarity index 66% rename from src/Workspaces/CoreTest/Options/OptionsTestHelpers.cs rename to src/Workspaces/CoreTestUtilities/Options/OptionsTestHelpers.cs index d27bd2731b9ca..6679471d9fa71 100644 --- a/src/Workspaces/CoreTest/Options/OptionsTestHelpers.cs +++ b/src/Workspaces/CoreTestUtilities/Options/OptionsTestHelpers.cs @@ -2,16 +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. +#pragma warning disable RS0030 // Do not used banned APIs + using System; +using System.Collections; using System.Collections.Generic; using System.Collections.Immutable; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Formatting; +using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Utilities; +using Xunit; namespace Microsoft.CodeAnalysis.UnitTests { @@ -24,7 +28,7 @@ internal static class OptionsTestHelpers (CustomPublicOption, false)); public static readonly ImmutableArray<(IOption, object)> PublicAutoFormattingOptionsWithNonDefaultValues = ImmutableArray.Create<(IOption, object)>( - (FormattingOptions.SmartIndent, FormattingOptions2.IndentStyle.Block)); + (FormattingOptions.SmartIndent, FormattingOptions.IndentStyle.Block)); public static readonly ImmutableArray<(IOption, object)> PublicFormattingOptionsWithNonDefaultValues = ImmutableArray.Create<(IOption, object)>( (FormattingOptions.UseTabs, true), @@ -108,6 +112,58 @@ public static OptionSet GetOptionSetWithChangedOptions(OptionSet options, IEnume } public static IEnumerable GetApplicableLanguages(IOption option) - => (option is IPerLanguageValuedOption) ? new[] { LanguageNames.CSharp, LanguageNames.VisualBasic } : new string?[] { null }; + => option.IsPerLanguage ? new[] { LanguageNames.CSharp, LanguageNames.VisualBasic } : new string?[] { null }; + + public static object? GetDifferentValue(Type type, object? value) + => value switch + { + _ when type == typeof(bool) => !(bool)value!, + _ when type == typeof(string) => (string?)value == "X" ? "Y" : "X", + _ when type == typeof(int) => (int)value! == 0 ? 1 : 0, + _ when type == typeof(long) => (long)value! == 0 ? 1L : 0L, + _ when type.IsEnum => GetDifferentEnumValue(type, value!), + ICodeStyleOption codeStyle => codeStyle + .WithValue(GetDifferentValue(codeStyle.GetType().GetGenericArguments()[0], codeStyle.Value!)!) + .WithNotification((codeStyle.Notification == NotificationOption2.Error) ? NotificationOption2.Warning : NotificationOption2.Error), + NamingStylePreferences namingPreference => namingPreference.IsEmpty ? NamingStylePreferences.Default : NamingStylePreferences.Empty, + _ when type == typeof(bool?) => value is null ? true : null, + _ 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.Empty, + ImmutableArray array => array is ["X"] ? ImmutableArray.Create("X", "Y") : ImmutableArray.Create("X"), + ImmutableArray array => array.IsEmpty ? ImmutableArray.Create(1) : ImmutableArray.Empty, + ImmutableArray array => array.IsEmpty ? ImmutableArray.Create(1L) : ImmutableArray.Empty, + + // Hit when a new option is introduced that uses type not handled above: + _ => throw ExceptionUtilities.UnexpectedValue(type) + }; + + private static object GetDifferentEnumValue(Type type, object defaultValue) + { + var zero = Enum.ToObject(type, 0); + return defaultValue.Equals(zero) ? Enum.ToObject(type, 1) : zero; + } + + /// + /// True if the type is a type of an option value. + /// + public static bool IsOptionValueType(Type type) + => type == typeof(bool) || + type == typeof(string) || + type == typeof(int) || + type == typeof(long) || + type == typeof(bool?) || + type == typeof(int?) || + type == typeof(long?) || + type.IsEnum || + typeof(ICodeStyleOption).IsAssignableFrom(type) || + type == typeof(NamingStylePreferences) || + type == typeof(ImmutableArray) || + type == typeof(ImmutableArray) || + type == typeof(ImmutableArray) || + type == typeof(ImmutableArray); + + public static Type GetNonNullableType(Type type) + => type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>) ? type.GetGenericArguments()[0] : type; } } diff --git a/src/Workspaces/CoreTestUtilities/Options/OptionsTestInfo.cs b/src/Workspaces/CoreTestUtilities/Options/OptionsTestInfo.cs new file mode 100644 index 0000000000000..4a18933664e05 --- /dev/null +++ b/src/Workspaces/CoreTestUtilities/Options/OptionsTestInfo.cs @@ -0,0 +1,77 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using Microsoft.CodeAnalysis.Options; +using Xunit; + +namespace Microsoft.CodeAnalysis.UnitTests; + +internal readonly record struct OptionsTestInfo(IOption2 Option, string? ContainingAssemblyLanguage, List<(string qualifiedName, bool isPublic, IOption2 option)> Accessors) +{ + public static Dictionary CollectOptions(string directory) + { + var result = new Dictionary(); + foreach (var file in Directory.EnumerateFiles(directory, "*.dll", SearchOption.TopDirectoryOnly)) + { + var fileName = Path.GetFileNameWithoutExtension(file); + if ((fileName.StartsWith("Microsoft.CodeAnalysis") || fileName.StartsWith("Microsoft.VisualStudio.LanguageServices")) && + !fileName.Contains("Test")) + { + Type[] types; + try + { + types = Assembly.Load(fileName).GetTypes(); + } + catch + { + continue; + } + + var language = file.Contains("CSharp") ? "CSharp" : file.Contains("VisualBasic") ? "VisualBasic" : null; + + foreach (var type in types) + { + foreach (var field in type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)) + { + if (field.Name.Contains("SpacingAfterMethodDeclarationName")) + { + } + + if (typeof(IOption2).IsAssignableFrom(field.FieldType)) + { + Assert.False(type.IsGenericType, "Option should not be defined in a generic type"); + + var option = (IOption2)field.GetValue(null)!; + Assert.NotNull(option); + + var isBackingField = field.Name.EndsWith("k__BackingField"); + var unmangledName = isBackingField ? field.Name[(field.Name.IndexOf('<') + 1)..field.Name.IndexOf('>')] : field.Name; + var accessor = type.FullName + "." + unmangledName; + var isPublic = type.IsPublic && (isBackingField ? type.GetProperty(unmangledName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)!.GetMethod!.IsPublic : field.IsPublic); + + var configName = option.Definition.ConfigName; + if (result.TryGetValue(configName, out var optionInfo)) + { + optionInfo.Accessors.Add((accessor, isPublic, option)); + } + else + { + optionInfo = new OptionsTestInfo(option, language, new List<(string, bool, IOption2)> { (accessor, isPublic, option) }); + } + + result[configName] = optionInfo; + } + } + } + } + } + + return result; + } +} diff --git a/src/Workspaces/CoreTestUtilities/Options/TestOption.cs b/src/Workspaces/CoreTestUtilities/Options/TestOption.cs new file mode 100644 index 0000000000000..243238ee85c7f --- /dev/null +++ b/src/Workspaces/CoreTestUtilities/Options/TestOption.cs @@ -0,0 +1,38 @@ +// 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.Options; + +namespace Microsoft.CodeAnalysis.UnitTests; + +internal class TestOption : IOption +{ + public string Feature { get; set; } = "test"; + public string Name { get; set; } = "test"; + public Type Type { get; set; } = typeof(int); + public object? DefaultValue { get; set; } = 1; + public bool IsPerLanguage { get; set; } + public ImmutableArray StorageLocations { get; set; } +} + +#pragma warning disable RS0030 // Do not used banned APIs + +internal class TestOption : Option +{ + public TestOption(string feature = "test", string name = "test", T? defaultValue = default, OptionStorageLocation[]? storageLocations = null) + : base(feature, name, defaultValue!, storageLocations ?? Array.Empty()) + { + } +} + +internal class PerLanguageTestOption : PerLanguageOption +{ + public PerLanguageTestOption(string feature = "test", string name = "test", T? defaultValue = default, OptionStorageLocation[]? storageLocations = null) + : base(feature, name, defaultValue!, storageLocations ?? Array.Empty()) + { + } +} +#pragma warning restore diff --git a/src/Workspaces/CoreTestUtilities/OptionsCollection.cs b/src/Workspaces/CoreTestUtilities/OptionsCollection.cs index 9866211c48681..2291627f86490 100644 --- a/src/Workspaces/CoreTestUtilities/OptionsCollection.cs +++ b/src/Workspaces/CoreTestUtilities/OptionsCollection.cs @@ -9,6 +9,8 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Options; +using System.Diagnostics; +using Microsoft.CodeAnalysis.Test.Utilities; #if !NETCOREAPP using System; @@ -17,7 +19,7 @@ namespace Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions { - internal sealed class OptionsCollection : IReadOnlyCollection> + internal sealed class OptionsCollection : IReadOnlyCollection>, IOptionsReader { private readonly Dictionary _options = new(); private readonly string _languageName; @@ -31,26 +33,33 @@ public OptionsCollection(string languageName) public int Count => _options.Count; + public void Add(OptionKey2 optionKey, T value) + { + // Can only add internally defined option whose storage is not mapped to another option: + Debug.Assert(optionKey.Option is IOption2 { Definition.StorageMapping: null }); + _options.Add(optionKey, value); + } + public void Set(Option2 option, T value) => _options[new OptionKey2(option)] = value; public void Add(Option2 option, T value) - => _options.Add(new OptionKey2(option), value); + => Add(new OptionKey2(option), value); public void Add(Option2> option, T value) => Add(option, value, option.DefaultValue.Notification); public void Add(Option2> option, T value, NotificationOption2 notification) - => _options.Add(new OptionKey2(option), new CodeStyleOption2(value, notification)); + => Add(new OptionKey2(option), new CodeStyleOption2(value, notification)); public void Add(PerLanguageOption2 option, T value) - => _options.Add(new OptionKey2(option, _languageName), value); + => Add(new OptionKey2(option, _languageName), value); public void Add(PerLanguageOption2> option, T value) => Add(option, value, option.DefaultValue.Notification); public void Add(PerLanguageOption2> option, T value, NotificationOption2 notification) - => _options.Add(new OptionKey2(option, _languageName), new CodeStyleOption2(value, notification)); + => Add(new OptionKey2(option, _languageName), new CodeStyleOption2(value, notification)); // 📝 This can be removed if/when collection initializers support AddRange. public void Add(OptionsCollection? options) @@ -73,21 +82,27 @@ IEnumerator IEnumerable.GetEnumerator() #if !CODE_STYLE public OptionSet ToOptionSet() - => new OptionValueSet(_options.ToImmutableDictionary(entry => new OptionKey(entry.Key.Option, entry.Key.Language), entry => entry.Value)); - - public AnalyzerConfigOptions ToAnalyzerConfigOptions(LanguageServices languageServices) - { - var optionService = languageServices.SolutionServices.GetRequiredService(); - return ToOptionSet().AsAnalyzerConfigOptions(optionService, languageServices.Language); - } + => new TestOptionSet(_options.ToImmutableDictionary(entry => new OptionKey(entry.Key.Option, entry.Key.Language), entry => entry.Value)); public void SetGlobalOptions(IGlobalOptionService globalOptions) { foreach (var (optionKey, value) in _options) { - globalOptions.SetGlobalOption((OptionKey)optionKey, value); + globalOptions.SetGlobalOption(optionKey, value); } } #endif + + public bool TryGetOption(OptionKey2 optionKey, out T value) + { + if (_options.TryGetValue(optionKey, out var objValue)) + { + value = (T)objValue!; + return true; + } + + value = default!; + return false; + } } } diff --git a/src/Workspaces/Remote/Core/Microsoft.CodeAnalysis.Remote.Workspaces.csproj b/src/Workspaces/Remote/Core/Microsoft.CodeAnalysis.Remote.Workspaces.csproj index 7f25e5b44f187..23ee18bb69462 100644 --- a/src/Workspaces/Remote/Core/Microsoft.CodeAnalysis.Remote.Workspaces.csproj +++ b/src/Workspaces/Remote/Core/Microsoft.CodeAnalysis.Remote.Workspaces.csproj @@ -45,6 +45,7 @@ + diff --git a/src/Workspaces/Remote/Core/ProjectSystem/IWorkspaceProject.cs b/src/Workspaces/Remote/Core/ProjectSystem/IWorkspaceProject.cs index 9b0b5e5ceec09..7075210fe2bce 100644 --- a/src/Workspaces/Remote/Core/ProjectSystem/IWorkspaceProject.cs +++ b/src/Workspaces/Remote/Core/ProjectSystem/IWorkspaceProject.cs @@ -33,5 +33,10 @@ internal interface IWorkspaceProject : IAsyncDisposable Task AddAnalyzerConfigFilesAsync(IReadOnlyList analyzerConfigPaths, CancellationToken cancellationToken); Task RemoveAnalyzerConfigFilesAsync(IReadOnlyList analyzerConfigPaths, CancellationToken cancellationToken); + Task AddDynamicFilesAsync(IReadOnlyList dynamicFilePaths, CancellationToken cancellationToken); + Task RemoveDynamicFilesAsync(IReadOnlyList dynamicFilePaths, CancellationToken cancellationToken); + + Task SetProjectHasAllInformationAsync(bool hasAllInformation, CancellationToken cancellationToken); + Task StartBatchAsync(CancellationToken cancellationToken); } diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.cs.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.cs.xlf index 3d8f90441525c..4d2fe680c9d75 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.cs.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.cs.xlf @@ -69,7 +69,7 @@ Fully qualify - Fully qualify + Plně kvalifikovat @@ -84,7 +84,7 @@ Solution Events - Solution Events + Události řešení @@ -149,7 +149,7 @@ Unit testing search - Unit testing search + Hledání v testování částí diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.de.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.de.xlf index a28d0b7a49a7a..3030bc0c5285a 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.de.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.de.xlf @@ -69,7 +69,7 @@ Fully qualify - Fully qualify + Vollqualifiziert @@ -84,7 +84,7 @@ Solution Events - Solution Events + Lösungsereignisse @@ -149,7 +149,7 @@ Unit testing search - Unit testing search + Komponententestsuche diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.es.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.es.xlf index 7a56a011f2068..c044db0411af2 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.es.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.es.xlf @@ -69,7 +69,7 @@ Fully qualify - Fully qualify + Completo @@ -84,7 +84,7 @@ Solution Events - Solution Events + Eventos de solución @@ -149,7 +149,7 @@ Unit testing search - Unit testing search + Búsqueda de pruebas unitarias diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.fr.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.fr.xlf index 417f5b75798b2..9204f1cb63ba3 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.fr.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.fr.xlf @@ -69,7 +69,7 @@ Fully qualify - Fully qualify + Qualifier entièrement @@ -84,7 +84,7 @@ Solution Events - Solution Events + Événements de solution @@ -149,7 +149,7 @@ Unit testing search - Unit testing search + Recherche de tests unitaires diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.it.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.it.xlf index b16c681e9929b..5bb6ef7bc453a 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.it.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.it.xlf @@ -69,7 +69,7 @@ Fully qualify - Fully qualify + Qualificare completamente @@ -84,7 +84,7 @@ Solution Events - Solution Events + Eventi della soluzione @@ -149,7 +149,7 @@ Unit testing search - Unit testing search + Ricerca unit test diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.ja.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.ja.xlf index 58ffd224d5719..6e04d7cdefcdf 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.ja.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.ja.xlf @@ -69,7 +69,7 @@ Fully qualify - Fully qualify + 完全修飾 @@ -84,7 +84,7 @@ Solution Events - Solution Events + ソリューション イベント @@ -149,7 +149,7 @@ Unit testing search - Unit testing search + 単体テストの検索 diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.ko.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.ko.xlf index 2ae395d83507e..b613c816d0b72 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.ko.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.ko.xlf @@ -84,7 +84,7 @@ Solution Events - Solution Events + 솔루션 이벤트 @@ -149,7 +149,7 @@ Unit testing search - Unit testing search + 단위 테스트 검색 diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.pl.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.pl.xlf index 7a6824bc4866e..5ab7b9f011d11 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.pl.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.pl.xlf @@ -84,7 +84,7 @@ Solution Events - Solution Events + Zdarzenia rozwiązania @@ -149,7 +149,7 @@ Unit testing search - Unit testing search + Wyszukiwanie testów jednostkowych diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.pt-BR.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.pt-BR.xlf index 4136429f52e8a..82e9c9ee6e9cb 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.pt-BR.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.pt-BR.xlf @@ -69,7 +69,7 @@ Fully qualify - Fully qualify + Totalmente qualificado @@ -84,7 +84,7 @@ Solution Events - Solution Events + Eventos da Solução @@ -149,7 +149,7 @@ Unit testing search - Unit testing search + Pesquisa de teste de unidade diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.ru.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.ru.xlf index df5479a787e2f..806c2e6a3f72e 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.ru.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.ru.xlf @@ -69,7 +69,7 @@ Fully qualify - Fully qualify + Определить полностью @@ -84,7 +84,7 @@ Solution Events - Solution Events + События решения @@ -149,7 +149,7 @@ Unit testing search - Unit testing search + Поиск модульного тестирования diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.tr.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.tr.xlf index 25ecd37a978a4..ac1a63e51d935 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.tr.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.tr.xlf @@ -69,7 +69,7 @@ Fully qualify - Fully qualify + Tam olarak nitele @@ -84,7 +84,7 @@ Solution Events - Solution Events + Çözüm Olayları @@ -149,7 +149,7 @@ Unit testing search - Unit testing search + Birim testi araması diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.zh-Hans.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.zh-Hans.xlf index 298dc4ea4eb68..8733739aee9b7 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.zh-Hans.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.zh-Hans.xlf @@ -69,7 +69,7 @@ Fully qualify - Fully qualify + 完全限定 @@ -84,7 +84,7 @@ Solution Events - Solution Events + 解决方案事件 @@ -149,7 +149,7 @@ Unit testing search - Unit testing search + 单元测试搜索 diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.zh-Hant.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.zh-Hant.xlf index 9f8737e696420..3e844f7e730d8 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.zh-Hant.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.zh-Hant.xlf @@ -69,7 +69,7 @@ Fully qualify - Fully qualify + 完全符合資格 @@ -84,7 +84,7 @@ Solution Events - Solution Events + 解决方案事件 @@ -149,7 +149,7 @@ Unit testing search - Unit testing search + 單元測試搜尋 diff --git a/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.cs b/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.cs index bee7f094897bc..ae74efc25a0d3 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.cs @@ -309,9 +309,11 @@ private async Task TryUpdateWorkspaceCurrentSolutionAsync( // Ensure we update newSolution with the result of SetCurrentSolution. It will be the one appropriately // 'attached' to this workspace. (_, newSolution) = this.SetCurrentSolution( - (oldSolution, _) => newSolution, - data: /*unused*/0, - onBeforeUpdate: (oldSolution, newSolution, _) => + _ => newSolution, + changeKind: static (oldSolution, newSolution) => IsAddingSolution(oldSolution, newSolution) + ? WorkspaceChangeKind.SolutionAdded + : WorkspaceChangeKind.SolutionChanged, + onBeforeUpdate: (oldSolution, newSolution) => { if (IsAddingSolution(oldSolution, newSolution)) { @@ -320,12 +322,6 @@ private async Task TryUpdateWorkspaceCurrentSolutionAsync( // this seems suspect as the remote workspace should not be tracking any open document state. this.ClearSolutionData(); } - }, - onAfterUpdate: (oldSolution, newSolution, _) => - { - RaiseWorkspaceChangedEventAsync( - IsAddingSolution(oldSolution, newSolution) ? WorkspaceChangeKind.SolutionAdded : WorkspaceChangeKind.SolutionChanged, - oldSolution, newSolution); }); return (newSolution, updated: true); diff --git a/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/PerformanceQueue.cs b/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/PerformanceQueue.cs index cf14031c1c95f..f2671c23f53e0 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/PerformanceQueue.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/PerformanceQueue.cs @@ -206,22 +206,32 @@ public int GetUniqueNumber(DiagnosticAnalyzer analyzer) public int GetUniqueNumber(string analyzerName) { - if (!_idMap.TryGetValue(analyzerName, out var id)) + // AnalyzerNumberAssigner.Instance can be accessed concurrently from different PerformanceQueue instances, + // so we need to take a lock on '_idMap' for all read/write operations. + lock (_idMap) { - id = _currentId++; - _idMap.Add(analyzerName, id); - } + if (!_idMap.TryGetValue(analyzerName, out var id)) + { + id = _currentId++; + _idMap.Add(analyzerName, id); + } - return id; + return id; + } } public void GetReverseMap(Dictionary reverseMap) { reverseMap.Clear(); - foreach (var kv in _idMap) + // AnalyzerNumberAssigner.Instance can be accessed concurrently from different PerformanceQueue instances, + // so we need to take a lock on '_idMap' for all read/write operations. + lock (_idMap) { - reverseMap.Add(kv.Value, kv.Key); + foreach (var kv in _idMap) + { + reverseMap.Add(kv.Value, kv.Key); + } } } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/ProcessTelemetry/RemoteWorkspaceConfigurationService.cs b/src/Workspaces/Remote/ServiceHub/Services/ProcessTelemetry/RemoteWorkspaceConfigurationService.cs index 61824f13f6e54..5acccbc75aacb 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/ProcessTelemetry/RemoteWorkspaceConfigurationService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/ProcessTelemetry/RemoteWorkspaceConfigurationService.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.Host { - [ExportWorkspaceService(typeof(IWorkspaceConfigurationService)), Shared] + [ExportWorkspaceService(typeof(IWorkspaceConfigurationService), ServiceLayer.Host), Shared] internal sealed class RemoteWorkspaceConfigurationService : IWorkspaceConfigurationService { private WorkspaceConfigurationOptions? _options; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeGeneration/CSharpCodeGenerationOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeGeneration/CSharpCodeGenerationOptions.cs index fec7b194448a8..7302244ce4aba 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeGeneration/CSharpCodeGenerationOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeGeneration/CSharpCodeGenerationOptions.cs @@ -85,23 +85,23 @@ public override CodeGenerationContextInfo GetInfo(CodeGenerationContext context, internal static class CSharpCodeGenerationOptionsProviders { - public static CSharpCodeGenerationOptions GetCSharpCodeGenerationOptions(this AnalyzerConfigOptions options, CSharpCodeGenerationOptions? fallbackOptions) + public static CSharpCodeGenerationOptions GetCSharpCodeGenerationOptions(this IOptionsReader options, CSharpCodeGenerationOptions? fallbackOptions) { fallbackOptions ??= CSharpCodeGenerationOptions.Default; return new() { - Common = options.GetCommonCodeGenerationOptions(fallbackOptions.Common), - PreferExpressionBodiedMethods = options.GetEditorConfigOption(CSharpCodeStyleOptions.PreferExpressionBodiedMethods, fallbackOptions.PreferExpressionBodiedMethods), - PreferExpressionBodiedAccessors = options.GetEditorConfigOption(CSharpCodeStyleOptions.PreferExpressionBodiedAccessors, fallbackOptions.PreferExpressionBodiedAccessors), - PreferExpressionBodiedProperties = options.GetEditorConfigOption(CSharpCodeStyleOptions.PreferExpressionBodiedProperties, fallbackOptions.PreferExpressionBodiedProperties), - PreferExpressionBodiedIndexers = options.GetEditorConfigOption(CSharpCodeStyleOptions.PreferExpressionBodiedIndexers, fallbackOptions.PreferExpressionBodiedIndexers), - PreferExpressionBodiedConstructors = options.GetEditorConfigOption(CSharpCodeStyleOptions.PreferExpressionBodiedConstructors, fallbackOptions.PreferExpressionBodiedConstructors), - PreferExpressionBodiedOperators = options.GetEditorConfigOption(CSharpCodeStyleOptions.PreferExpressionBodiedOperators, fallbackOptions.PreferExpressionBodiedOperators), - PreferExpressionBodiedLocalFunctions = options.GetEditorConfigOption(CSharpCodeStyleOptions.PreferExpressionBodiedLocalFunctions, fallbackOptions.PreferExpressionBodiedLocalFunctions), - PreferExpressionBodiedLambdas = options.GetEditorConfigOption(CSharpCodeStyleOptions.PreferExpressionBodiedLambdas, fallbackOptions.PreferExpressionBodiedLambdas), - PreferStaticLocalFunction = options.GetEditorConfigOption(CSharpCodeStyleOptions.PreferStaticLocalFunction, fallbackOptions.PreferStaticLocalFunction), - NamespaceDeclarations = options.GetEditorConfigOption(CSharpCodeStyleOptions.NamespaceDeclarations, fallbackOptions.NamespaceDeclarations) + Common = options.GetCommonCodeGenerationOptions(LanguageNames.CSharp, fallbackOptions.Common), + PreferExpressionBodiedMethods = options.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedMethods, fallbackOptions.PreferExpressionBodiedMethods), + PreferExpressionBodiedAccessors = options.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedAccessors, fallbackOptions.PreferExpressionBodiedAccessors), + PreferExpressionBodiedProperties = options.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedProperties, fallbackOptions.PreferExpressionBodiedProperties), + PreferExpressionBodiedIndexers = options.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedIndexers, fallbackOptions.PreferExpressionBodiedIndexers), + PreferExpressionBodiedConstructors = options.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedConstructors, fallbackOptions.PreferExpressionBodiedConstructors), + PreferExpressionBodiedOperators = options.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedOperators, fallbackOptions.PreferExpressionBodiedOperators), + PreferExpressionBodiedLocalFunctions = options.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedLocalFunctions, fallbackOptions.PreferExpressionBodiedLocalFunctions), + PreferExpressionBodiedLambdas = options.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedLambdas, fallbackOptions.PreferExpressionBodiedLambdas), + PreferStaticLocalFunction = options.GetOption(CSharpCodeStyleOptions.PreferStaticLocalFunction, fallbackOptions.PreferStaticLocalFunction), + NamespaceDeclarations = options.GetOption(CSharpCodeStyleOptions.NamespaceDeclarations, fallbackOptions.NamespaceDeclarations) }; } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeStyle/CSharpCodeStyleOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeStyle/CSharpCodeStyleOptions.cs index 784d310cbbbd3..6354265172319 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeStyle/CSharpCodeStyleOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeStyle/CSharpCodeStyleOptions.cs @@ -2,12 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Linq; using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.CodeStyle; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.CSharp.Formatting; using Microsoft.CodeAnalysis.CSharp.Simplification; using Microsoft.CodeAnalysis.Options; @@ -16,134 +15,78 @@ namespace Microsoft.CodeAnalysis.CSharp.CodeStyle { internal static partial class CSharpCodeStyleOptions { - private static readonly CodeStyleOption2 s_trueWithSuggestionEnforcement = CodeStyleOptions2.TrueWithSuggestionEnforcement; - private static readonly CodeStyleOption2 s_trueWithSilentEnforcement = CodeStyleOptions2.TrueWithSilentEnforcement; - private static readonly ImmutableArray.Builder s_allOptionsBuilder = ImmutableArray.CreateBuilder(); - internal static ImmutableArray AllOptions { get; } - - private static Option2 CreateOption( - OptionGroup group, string name, T defaultValue, OptionStorageLocation2 storageLocation) - => CodeStyleHelpers.CreateOption( - group, nameof(CSharpCodeStyleOptions), name, defaultValue, - s_allOptionsBuilder, storageLocation, LanguageNames.CSharp); - - private static Option2 CreateOption( - OptionGroup group, string name, T defaultValue, OptionStorageLocation2 storageLocation1, OptionStorageLocation2 storageLocation2) - => CodeStyleHelpers.CreateOption( - group, nameof(CSharpCodeStyleOptions), name, defaultValue, - s_allOptionsBuilder, storageLocation1, storageLocation2, LanguageNames.CSharp); - - private static Option2> CreateOption( - OptionGroup group, string name, CodeStyleOption2 defaultValue, string editorconfigKeyName, string roamingProfileStorageKeyName) - => CreateOption( - group, name, defaultValue, - EditorConfigStorageLocation.ForBoolCodeStyleOption(editorconfigKeyName, defaultValue), - new RoamingProfileStorageLocation(roamingProfileStorageKeyName)); - - private static Option2> CreateOption( - OptionGroup group, string name, CodeStyleOption2 defaultValue, string editorconfigKeyName, string roamingProfileStorageKeyName) - => CreateOption( - group, name, defaultValue, - EditorConfigStorageLocation.ForStringCodeStyleOption(editorconfigKeyName, defaultValue), - new RoamingProfileStorageLocation(roamingProfileStorageKeyName)); + private static Option2> CreateOption( + OptionGroup group, + string name, + CodeStyleOption2 defaultValue, + Func, EditorConfigValueSerializer>>? serializerFactory = null) + => s_allOptionsBuilder.CreateEditorConfigOption(name, defaultValue, group, LanguageNames.CSharp, serializerFactory); public static readonly Option2> VarForBuiltInTypes = CreateOption( - CSharpCodeStyleOptionGroups.VarPreferences, nameof(VarForBuiltInTypes), - CSharpSimplifierOptions.Default.VarForBuiltInTypes, - "csharp_style_var_for_built_in_types", - "TextEditor.CSharp.Specific.UseImplicitTypeForIntrinsicTypes"); + CSharpCodeStyleOptionGroups.VarPreferences, "csharp_style_var_for_built_in_types", + CSharpSimplifierOptions.Default.VarForBuiltInTypes); public static readonly Option2> VarWhenTypeIsApparent = CreateOption( - CSharpCodeStyleOptionGroups.VarPreferences, nameof(VarWhenTypeIsApparent), - CSharpSimplifierOptions.Default.VarWhenTypeIsApparent, - "csharp_style_var_when_type_is_apparent", - "TextEditor.CSharp.Specific.UseImplicitTypeWhereApparent"); + CSharpCodeStyleOptionGroups.VarPreferences, "csharp_style_var_when_type_is_apparent", + CSharpSimplifierOptions.Default.VarWhenTypeIsApparent); public static readonly Option2> VarElsewhere = CreateOption( - CSharpCodeStyleOptionGroups.VarPreferences, nameof(VarElsewhere), - CSharpSimplifierOptions.Default.VarElsewhere, - "csharp_style_var_elsewhere", - "TextEditor.CSharp.Specific.UseImplicitTypeWherePossible"); + CSharpCodeStyleOptionGroups.VarPreferences, "csharp_style_var_elsewhere", + CSharpSimplifierOptions.Default.VarElsewhere); public static readonly Option2> PreferConditionalDelegateCall = CreateOption( - CSharpCodeStyleOptionGroups.NullCheckingPreferences, nameof(PreferConditionalDelegateCall), - CSharpIdeCodeStyleOptions.Default.PreferConditionalDelegateCall, - "csharp_style_conditional_delegate_call", - "TextEditor.CSharp.Specific.PreferConditionalDelegateCall"); + CSharpCodeStyleOptionGroups.NullCheckingPreferences, "csharp_style_conditional_delegate_call", + CSharpIdeCodeStyleOptions.Default.PreferConditionalDelegateCall); public static readonly Option2> PreferSwitchExpression = CreateOption( - CSharpCodeStyleOptionGroups.PatternMatching, nameof(PreferSwitchExpression), - CSharpIdeCodeStyleOptions.Default.PreferSwitchExpression, - "csharp_style_prefer_switch_expression", - "TextEditor.CSharp.Specific.PreferSwitchExpression"); + CSharpCodeStyleOptionGroups.PatternMatching, "csharp_style_prefer_switch_expression", + CSharpIdeCodeStyleOptions.Default.PreferSwitchExpression); public static readonly Option2> PreferPatternMatching = CreateOption( - CSharpCodeStyleOptionGroups.PatternMatching, nameof(PreferPatternMatching), - CSharpIdeCodeStyleOptions.Default.PreferPatternMatching, - "csharp_style_prefer_pattern_matching", - "TextEditor.CSharp.Specific.PreferPatternMatching"); + CSharpCodeStyleOptionGroups.PatternMatching, "csharp_style_prefer_pattern_matching", + CSharpIdeCodeStyleOptions.Default.PreferPatternMatching); public static readonly Option2> PreferPatternMatchingOverAsWithNullCheck = CreateOption( - CSharpCodeStyleOptionGroups.PatternMatching, nameof(PreferPatternMatchingOverAsWithNullCheck), - CSharpIdeCodeStyleOptions.Default.PreferPatternMatchingOverAsWithNullCheck, - "csharp_style_pattern_matching_over_as_with_null_check", - "TextEditor.CSharp.Specific.PreferPatternMatchingOverAsWithNullCheck"); + CSharpCodeStyleOptionGroups.PatternMatching, "csharp_style_pattern_matching_over_as_with_null_check", + CSharpIdeCodeStyleOptions.Default.PreferPatternMatchingOverAsWithNullCheck); public static readonly Option2> PreferPatternMatchingOverIsWithCastCheck = CreateOption( - CSharpCodeStyleOptionGroups.PatternMatching, nameof(PreferPatternMatchingOverIsWithCastCheck), - CSharpIdeCodeStyleOptions.Default.PreferPatternMatchingOverIsWithCastCheck, - "csharp_style_pattern_matching_over_is_with_cast_check", - "TextEditor.CSharp.Specific.PreferPatternMatchingOverIsWithCastCheck"); + CSharpCodeStyleOptionGroups.PatternMatching, "csharp_style_pattern_matching_over_is_with_cast_check", + CSharpIdeCodeStyleOptions.Default.PreferPatternMatchingOverIsWithCastCheck); public static readonly Option2> PreferNotPattern = CreateOption( - CSharpCodeStyleOptionGroups.PatternMatching, nameof(PreferNotPattern), - CSharpIdeCodeStyleOptions.Default.PreferNotPattern, - "csharp_style_prefer_not_pattern", - "TextEditor.CSharp.Specific.PreferNotPattern"); + CSharpCodeStyleOptionGroups.PatternMatching, "csharp_style_prefer_not_pattern", + CSharpIdeCodeStyleOptions.Default.PreferNotPattern); public static readonly Option2> PreferExtendedPropertyPattern = CreateOption( - CSharpCodeStyleOptionGroups.PatternMatching, nameof(PreferExtendedPropertyPattern), - CSharpIdeCodeStyleOptions.Default.PreferExtendedPropertyPattern, - "csharp_style_prefer_extended_property_pattern", - "TextEditor.CSharp.Specific.PreferExtendedPropertyPattern"); + CSharpCodeStyleOptionGroups.PatternMatching, "csharp_style_prefer_extended_property_pattern", + CSharpIdeCodeStyleOptions.Default.PreferExtendedPropertyPattern); public static readonly Option2> PreferThrowExpression = CreateOption( - CSharpCodeStyleOptionGroups.ExpressionLevelPreferences, nameof(PreferThrowExpression), - CSharpSimplifierOptions.Default.PreferThrowExpression, - "csharp_style_throw_expression", - "TextEditor.CSharp.Specific.PreferThrowExpression"); + CSharpCodeStyleOptionGroups.ExpressionLevelPreferences, "csharp_style_throw_expression", + CSharpSimplifierOptions.Default.PreferThrowExpression); public static readonly Option2> PreferInlinedVariableDeclaration = CreateOption( - CSharpCodeStyleOptionGroups.ExpressionLevelPreferences, nameof(PreferInlinedVariableDeclaration), - CSharpIdeCodeStyleOptions.Default.PreferInlinedVariableDeclaration, - "csharp_style_inlined_variable_declaration", - "TextEditor.CSharp.Specific.PreferInlinedVariableDeclaration"); + CSharpCodeStyleOptionGroups.ExpressionLevelPreferences, "csharp_style_inlined_variable_declaration", + CSharpIdeCodeStyleOptions.Default.PreferInlinedVariableDeclaration); public static readonly Option2> PreferDeconstructedVariableDeclaration = CreateOption( - CSharpCodeStyleOptionGroups.ExpressionLevelPreferences, nameof(PreferDeconstructedVariableDeclaration), - CSharpIdeCodeStyleOptions.Default.PreferDeconstructedVariableDeclaration, - "csharp_style_deconstructed_variable_declaration", - "TextEditor.CSharp.Specific.PreferDeconstructedVariableDeclaration"); + CSharpCodeStyleOptionGroups.ExpressionLevelPreferences, "csharp_style_deconstructed_variable_declaration", + CSharpIdeCodeStyleOptions.Default.PreferDeconstructedVariableDeclaration); public static readonly Option2> PreferIndexOperator = CreateOption( - CSharpCodeStyleOptionGroups.ExpressionLevelPreferences, nameof(PreferIndexOperator), - CSharpIdeCodeStyleOptions.Default.PreferIndexOperator, - "csharp_style_prefer_index_operator", - "TextEditor.CSharp.Specific.PreferIndexOperator"); + CSharpCodeStyleOptionGroups.ExpressionLevelPreferences, "csharp_style_prefer_index_operator", + CSharpIdeCodeStyleOptions.Default.PreferIndexOperator); public static readonly Option2> PreferRangeOperator = CreateOption( - CSharpCodeStyleOptionGroups.ExpressionLevelPreferences, nameof(PreferRangeOperator), - CSharpIdeCodeStyleOptions.Default.PreferRangeOperator, - "csharp_style_prefer_range_operator", - "TextEditor.CSharp.Specific.PreferRangeOperator"); + CSharpCodeStyleOptionGroups.ExpressionLevelPreferences, "csharp_style_prefer_range_operator", + CSharpIdeCodeStyleOptions.Default.PreferRangeOperator); public static readonly Option2> PreferUtf8StringLiterals = CreateOption( - CSharpCodeStyleOptionGroups.ExpressionLevelPreferences, "PreferUtf8StringLiterals", - CSharpIdeCodeStyleOptions.Default.PreferUtf8StringLiterals, - "csharp_style_prefer_utf8_string_literals", - $"TextEditor.CSharp.Specific.PreferUtf8StringLiterals"); + CSharpCodeStyleOptionGroups.ExpressionLevelPreferences, "csharp_style_prefer_utf8_string_literals", + CSharpIdeCodeStyleOptions.Default.PreferUtf8StringLiterals); public static readonly CodeStyleOption2 NeverWithSilentEnforcement = new(ExpressionBodyPreference.Never, NotificationOption2.Silent); @@ -160,269 +103,163 @@ private static Option2> CreateOption( public static readonly CodeStyleOption2 WhenOnSingleLineWithSilentEnforcement = new(ExpressionBodyPreference.WhenOnSingleLine, NotificationOption2.Silent); - private static Option2> CreatePreferExpressionBodyOption( - string optionName, - CodeStyleOption2 defaultValue, - string editorconfigKeyName) - => CreateOption( - CSharpCodeStyleOptionGroups.ExpressionBodiedMembers, optionName, - defaultValue, - new EditorConfigStorageLocation>( - editorconfigKeyName, - s => ParseExpressionBodyPreference(s, defaultValue), - v => GetExpressionBodyPreferenceEditorConfigString(v, defaultValue)), - new RoamingProfileStorageLocation($"TextEditor.CSharp.Specific.{optionName}")); + private static Option2> CreatePreferExpressionBodyOption(CodeStyleOption2 defaultValue, string name) + => CreateOption(CSharpCodeStyleOptionGroups.ExpressionBodiedMembers, name, defaultValue, defaultValue => + new(parseValue: str => ParseExpressionBodyPreference(str, defaultValue), + serializeValue: value => GetExpressionBodyPreferenceEditorConfigString(value, defaultValue))); public static readonly Option2> PreferExpressionBodiedConstructors = CreatePreferExpressionBodyOption( - nameof(PreferExpressionBodiedConstructors), defaultValue: NeverWithSilentEnforcement, "csharp_style_expression_bodied_constructors"); + defaultValue: NeverWithSilentEnforcement, name: "csharp_style_expression_bodied_constructors"); public static readonly Option2> PreferExpressionBodiedMethods = CreatePreferExpressionBodyOption( - nameof(PreferExpressionBodiedMethods), defaultValue: NeverWithSilentEnforcement, "csharp_style_expression_bodied_methods"); + defaultValue: NeverWithSilentEnforcement, name: "csharp_style_expression_bodied_methods"); public static readonly Option2> PreferExpressionBodiedOperators = CreatePreferExpressionBodyOption( - nameof(PreferExpressionBodiedOperators), defaultValue: NeverWithSilentEnforcement, "csharp_style_expression_bodied_operators"); + defaultValue: NeverWithSilentEnforcement, name: "csharp_style_expression_bodied_operators"); public static readonly Option2> PreferExpressionBodiedProperties = CreatePreferExpressionBodyOption( - nameof(PreferExpressionBodiedProperties), defaultValue: WhenPossibleWithSilentEnforcement, "csharp_style_expression_bodied_properties"); + defaultValue: WhenPossibleWithSilentEnforcement, name: "csharp_style_expression_bodied_properties"); public static readonly Option2> PreferExpressionBodiedIndexers = CreatePreferExpressionBodyOption( - nameof(PreferExpressionBodiedIndexers), defaultValue: WhenPossibleWithSilentEnforcement, "csharp_style_expression_bodied_indexers"); + defaultValue: WhenPossibleWithSilentEnforcement, name: "csharp_style_expression_bodied_indexers"); public static readonly Option2> PreferExpressionBodiedAccessors = CreatePreferExpressionBodyOption( - nameof(PreferExpressionBodiedAccessors), defaultValue: WhenPossibleWithSilentEnforcement, "csharp_style_expression_bodied_accessors"); + defaultValue: WhenPossibleWithSilentEnforcement, name: "csharp_style_expression_bodied_accessors"); public static readonly Option2> PreferExpressionBodiedLambdas = CreatePreferExpressionBodyOption( - nameof(PreferExpressionBodiedLambdas), defaultValue: WhenPossibleWithSilentEnforcement, "csharp_style_expression_bodied_lambdas"); + defaultValue: WhenPossibleWithSilentEnforcement, name: "csharp_style_expression_bodied_lambdas"); public static readonly Option2> PreferExpressionBodiedLocalFunctions = CreatePreferExpressionBodyOption( - nameof(PreferExpressionBodiedLocalFunctions), defaultValue: NeverWithSilentEnforcement, "csharp_style_expression_bodied_local_functions"); - - private static Option2> CreatePreferBracesOption( - string optionName, - CodeStyleOption2 defaultValue, - string editorconfigKeyName) - => CreateOption( - CSharpCodeStyleOptionGroups.CodeBlockPreferences, optionName, - defaultValue, - new EditorConfigStorageLocation>( - editorconfigKeyName, - s => ParsePreferBracesPreference(s, defaultValue), - v => GetPreferBracesPreferenceEditorConfigString(v, defaultValue)), - new RoamingProfileStorageLocation($"TextEditor.CSharp.Specific.{optionName}")); - - public static readonly Option2> PreferBraces = CreatePreferBracesOption( - nameof(PreferBraces), CSharpSimplifierOptions.Default.PreferBraces, "csharp_prefer_braces"); + defaultValue: NeverWithSilentEnforcement, name: "csharp_style_expression_bodied_local_functions"); + + public static readonly Option2> PreferBraces = CreateOption( + CSharpCodeStyleOptionGroups.CodeBlockPreferences, + "csharp_prefer_braces", + CSharpSimplifierOptions.Default.PreferBraces, + defaultValue => new( + parseValue: str => ParsePreferBracesPreference(str, defaultValue), + serializeValue: value => GetPreferBracesPreferenceEditorConfigString(value, defaultValue))); public static readonly Option2> PreferSimpleDefaultExpression = CreateOption( - CSharpCodeStyleOptionGroups.ExpressionLevelPreferences, nameof(PreferSimpleDefaultExpression), - CSharpSimplifierOptions.Default.PreferSimpleDefaultExpression, + CSharpCodeStyleOptionGroups.ExpressionLevelPreferences, "csharp_prefer_simple_default_expression", - "TextEditor.CSharp.Specific.PreferSimpleDefaultExpression"); + CSharpSimplifierOptions.Default.PreferSimpleDefaultExpression); public static readonly Option2> PreferredModifierOrder = CreateOption( - CSharpCodeStyleOptionGroups.Modifier, nameof(PreferredModifierOrder), - CSharpIdeCodeStyleOptions.Default.PreferredModifierOrder, + CSharpCodeStyleOptionGroups.Modifier, "csharp_preferred_modifier_order", - "TextEditor.CSharp.Specific.PreferredModifierOrder"); + CSharpIdeCodeStyleOptions.Default.PreferredModifierOrder); public static readonly Option2> PreferStaticLocalFunction = CreateOption( - CSharpCodeStyleOptionGroups.Modifier, nameof(PreferStaticLocalFunction), - CSharpIdeCodeStyleOptions.Default.PreferStaticLocalFunction, + CSharpCodeStyleOptionGroups.Modifier, "csharp_prefer_static_local_function", - "TextEditor.CSharp.Specific.PreferStaticLocalFunction"); + CSharpIdeCodeStyleOptions.Default.PreferStaticLocalFunction); public static readonly Option2> PreferReadOnlyStruct = CreateOption( - CSharpCodeStyleOptionGroups.Modifier, nameof(PreferReadOnlyStruct), - CSharpIdeCodeStyleOptions.Default.PreferReadOnlyStruct, + CSharpCodeStyleOptionGroups.Modifier, "csharp_style_prefer_readonly_struct", - "TextEditor.CSharp.Specific.PreferReadOnlyStruct"); + CSharpIdeCodeStyleOptions.Default.PreferReadOnlyStruct); public static readonly Option2> PreferSimpleUsingStatement = CreateOption( - CSharpCodeStyleOptionGroups.CodeBlockPreferences, nameof(PreferSimpleUsingStatement), - CSharpIdeCodeStyleOptions.Default.PreferSimpleUsingStatement, + CSharpCodeStyleOptionGroups.CodeBlockPreferences, "csharp_prefer_simple_using_statement", - "TextEditor.CSharp.Specific.PreferSimpleUsingStatement"); + CSharpIdeCodeStyleOptions.Default.PreferSimpleUsingStatement); public static readonly Option2> PreferLocalOverAnonymousFunction = CreateOption( - CSharpCodeStyleOptionGroups.ExpressionLevelPreferences, nameof(PreferLocalOverAnonymousFunction), - CSharpIdeCodeStyleOptions.Default.PreferLocalOverAnonymousFunction, + CSharpCodeStyleOptionGroups.ExpressionLevelPreferences, "csharp_style_prefer_local_over_anonymous_function", - "TextEditor.CSharp.Specific.PreferLocalOverAnonymousFunction"); + CSharpIdeCodeStyleOptions.Default.PreferLocalOverAnonymousFunction); public static readonly Option2> PreferTupleSwap = CreateOption( - CSharpCodeStyleOptionGroups.ExpressionLevelPreferences, nameof(PreferTupleSwap), - CSharpIdeCodeStyleOptions.Default.PreferTupleSwap, - "csharp_style_prefer_tuple_swap", - "TextEditor.CSharp.Specific.PreferTupleSwap"); - - public static readonly CodeStyleOption2 PreferOutsidePlacementWithSilentEnforcement = - new(AddImportPlacement.OutsideNamespace, NotificationOption2.Silent); - - private static Option2> CreateUsingDirectivePlacementOption(string optionName, CodeStyleOption2 defaultValue, string editorconfigKeyName) - => CreateOption( - CSharpCodeStyleOptionGroups.UsingDirectivePreferences, optionName, - defaultValue, - new EditorConfigStorageLocation>( - editorconfigKeyName, - s => ParseUsingDirectivesPlacement(s, defaultValue), - v => GetUsingDirectivesPlacementEditorConfigString(v, defaultValue)), - new RoamingProfileStorageLocation($"TextEditor.CSharp.Specific.{optionName}")); - - public static readonly Option2> PreferredUsingDirectivePlacement = CreateUsingDirectivePlacementOption( - "PreferredUsingDirectivePlacement", AddImportPlacementOptions.Default.UsingDirectivePlacement, "csharp_using_directive_placement"); - - internal static readonly Option2> UnusedValueExpressionStatement = - CodeStyleHelpers.CreateUnusedExpressionAssignmentOption( - CSharpCodeStyleOptionGroups.ExpressionLevelPreferences, - feature: nameof(CSharpCodeStyleOptions), - name: "UnusedValueExpressionStatement", - editorConfigName: "csharp_style_unused_value_expression_statement_preference", - CSharpIdeCodeStyleOptions.Default.UnusedValueExpressionStatement, - s_allOptionsBuilder, - LanguageNames.CSharp); - - internal static readonly Option2> UnusedValueAssignment = - CodeStyleHelpers.CreateUnusedExpressionAssignmentOption( - CSharpCodeStyleOptionGroups.ExpressionLevelPreferences, - feature: nameof(CSharpCodeStyleOptions), - name: "UnusedValueAssignment", - editorConfigName: "csharp_style_unused_value_assignment_preference", - CSharpIdeCodeStyleOptions.Default.UnusedValueAssignment, - s_allOptionsBuilder, - LanguageNames.CSharp); + CSharpCodeStyleOptionGroups.ExpressionLevelPreferences, "csharp_style_prefer_tuple_swap", + CSharpIdeCodeStyleOptions.Default.PreferTupleSwap); + + public static readonly Option2> PreferredUsingDirectivePlacement = CreateOption( + CSharpCodeStyleOptionGroups.UsingDirectivePreferences, + "csharp_using_directive_placement", + AddImportPlacementOptions.Default.UsingDirectivePlacement, + defaultValue => new( + parseValue: str => ParseUsingDirectivesPlacement(str, defaultValue), + serializeValue: value => GetUsingDirectivesPlacementEditorConfigString(value, defaultValue))); + + internal static readonly Option2> UnusedValueExpressionStatement = CreateOption( + CSharpCodeStyleOptionGroups.ExpressionLevelPreferences, + "csharp_style_unused_value_expression_statement_preference", + CSharpIdeCodeStyleOptions.Default.UnusedValueExpressionStatement, + serializerFactory: CodeStyleHelpers.GetUnusedValuePreferenceSerializer); + + internal static readonly Option2> UnusedValueAssignment = CreateOption( + CSharpCodeStyleOptionGroups.ExpressionLevelPreferences, + "csharp_style_unused_value_assignment_preference", + CSharpIdeCodeStyleOptions.Default.UnusedValueAssignment, + serializerFactory: CodeStyleHelpers.GetUnusedValuePreferenceSerializer); public static readonly Option2> ImplicitObjectCreationWhenTypeIsApparent = CreateOption( - CSharpCodeStyleOptionGroups.ExpressionLevelPreferences, nameof(ImplicitObjectCreationWhenTypeIsApparent), - CSharpIdeCodeStyleOptions.Default.ImplicitObjectCreationWhenTypeIsApparent, + CSharpCodeStyleOptionGroups.ExpressionLevelPreferences, "csharp_style_implicit_object_creation_when_type_is_apparent", - "TextEditor.CSharp.Specific.ImplicitObjectCreationWhenTypeIsApparent"); + CSharpIdeCodeStyleOptions.Default.ImplicitObjectCreationWhenTypeIsApparent); internal static readonly Option2> PreferNullCheckOverTypeCheck = CreateOption( - CSharpCodeStyleOptionGroups.ExpressionLevelPreferences, nameof(PreferNullCheckOverTypeCheck), - CSharpIdeCodeStyleOptions.Default.PreferNullCheckOverTypeCheck, + CSharpCodeStyleOptionGroups.ExpressionLevelPreferences, "csharp_style_prefer_null_check_over_type_check", - "TextEditor.CSharp.Specific.PreferNullCheckOverTypeCheck"); + CSharpIdeCodeStyleOptions.Default.PreferNullCheckOverTypeCheck); public static Option2> AllowEmbeddedStatementsOnSameLine { get; } = CreateOption( - CSharpCodeStyleOptionGroups.NewLinePreferences, nameof(AllowEmbeddedStatementsOnSameLine), - CSharpSimplifierOptions.Default.AllowEmbeddedStatementsOnSameLine, - EditorConfigStorageLocation.ForBoolCodeStyleOption("csharp_style_allow_embedded_statements_on_same_line_experimental", CodeStyleOptions2.TrueWithSilentEnforcement), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.AllowEmbeddedStatementsOnSameLine")); + CSharpCodeStyleOptionGroups.NewLinePreferences, + "csharp_style_allow_embedded_statements_on_same_line_experimental", + CSharpSimplifierOptions.Default.AllowEmbeddedStatementsOnSameLine); public static Option2> AllowBlankLinesBetweenConsecutiveBraces { get; } = CreateOption( - CSharpCodeStyleOptionGroups.NewLinePreferences, nameof(AllowBlankLinesBetweenConsecutiveBraces), - CSharpIdeCodeStyleOptions.Default.AllowBlankLinesBetweenConsecutiveBraces, - EditorConfigStorageLocation.ForBoolCodeStyleOption("csharp_style_allow_blank_lines_between_consecutive_braces_experimental", CodeStyleOptions2.TrueWithSilentEnforcement), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.AllowBlankLinesBetweenConsecutiveBraces")); + CSharpCodeStyleOptionGroups.NewLinePreferences, + "csharp_style_allow_blank_lines_between_consecutive_braces_experimental", + CSharpIdeCodeStyleOptions.Default.AllowBlankLinesBetweenConsecutiveBraces); public static Option2> AllowBlankLineAfterColonInConstructorInitializer { get; } = CreateOption( - CSharpCodeStyleOptionGroups.NewLinePreferences, nameof(AllowBlankLineAfterColonInConstructorInitializer), - CSharpIdeCodeStyleOptions.Default.AllowBlankLineAfterColonInConstructorInitializer, - EditorConfigStorageLocation.ForBoolCodeStyleOption("csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental", CodeStyleOptions2.TrueWithSilentEnforcement), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.AllowBlankLineAfterColonInConstructorInitializer")); + CSharpCodeStyleOptionGroups.NewLinePreferences, + "csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental", + CSharpIdeCodeStyleOptions.Default.AllowBlankLineAfterColonInConstructorInitializer); public static Option2> AllowBlankLineAfterTokenInConditionalExpression { get; } = CreateOption( - CSharpCodeStyleOptionGroups.NewLinePreferences, nameof(AllowBlankLineAfterTokenInConditionalExpression), - CSharpIdeCodeStyleOptions.Default.AllowBlankLineAfterTokenInConditionalExpression, - EditorConfigStorageLocation.ForBoolCodeStyleOption("csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental", CodeStyleOptions2.TrueWithSilentEnforcement), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.AllowBlankLineAfterTokenInConditionalExpression")); + CSharpCodeStyleOptionGroups.NewLinePreferences, + "csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental", + CSharpIdeCodeStyleOptions.Default.AllowBlankLineAfterTokenInConditionalExpression); public static Option2> AllowBlankLineAfterTokenInArrowExpressionClause { get; } = CreateOption( - CSharpCodeStyleOptionGroups.NewLinePreferences, nameof(AllowBlankLineAfterTokenInArrowExpressionClause), - CSharpIdeCodeStyleOptions.Default.AllowBlankLineAfterTokenInArrowExpressionClause, - EditorConfigStorageLocation.ForBoolCodeStyleOption("csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental", CodeStyleOptions2.TrueWithSilentEnforcement), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.AllowBlankLineAfterTokenInArrowExpressionClause")); - - private static Option2> CreateNamespaceDeclarationOption(string optionName, CodeStyleOption2 defaultValue, string editorconfigKeyName) - => CreateOption( - CSharpCodeStyleOptionGroups.CodeBlockPreferences, optionName, - defaultValue, - new EditorConfigStorageLocation>( - editorconfigKeyName, - s => ParseNamespaceDeclaration(s, defaultValue), - v => GetNamespaceDeclarationEditorConfigString(v, defaultValue)), - new RoamingProfileStorageLocation($"TextEditor.CSharp.Specific.{optionName}")); - - public static readonly Option2> NamespaceDeclarations = CreateNamespaceDeclarationOption( - "NamespaceDeclarations", + CSharpCodeStyleOptionGroups.NewLinePreferences, + "csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental", + CSharpIdeCodeStyleOptions.Default.AllowBlankLineAfterTokenInArrowExpressionClause); + + public static Option2> NamespaceDeclarations { get; } = CreateOption( + CSharpCodeStyleOptionGroups.CodeBlockPreferences, + "csharp_style_namespace_declarations", CSharpSyntaxFormattingOptions.Default.NamespaceDeclarations, - "csharp_style_namespace_declarations"); + defaultValue => new( + parseValue: str => ParseNamespaceDeclaration(str, defaultValue), + serializeValue: value => GetNamespaceDeclarationEditorConfigString(value, defaultValue))); public static readonly Option2> PreferMethodGroupConversion = CreateOption( - CSharpCodeStyleOptionGroups.CodeBlockPreferences, nameof(PreferMethodGroupConversion), - CSharpIdeCodeStyleOptions.Default.PreferMethodGroupConversion, + CSharpCodeStyleOptionGroups.CodeBlockPreferences, "csharp_style_prefer_method_group_conversion", - "TextEditor.CSharp.Specific.PreferMethodGroupConversion"); + CSharpIdeCodeStyleOptions.Default.PreferMethodGroupConversion); public static readonly Option2> PreferTopLevelStatements = CreateOption( - CSharpCodeStyleOptionGroups.CodeBlockPreferences, nameof(PreferTopLevelStatements), - CSharpSyntaxFormattingOptions.Default.PreferTopLevelStatements, + CSharpCodeStyleOptionGroups.CodeBlockPreferences, "csharp_style_prefer_top_level_statements", - "TextEditor.CSharp.Specific.PreferTopLevelStatements"); + CSharpSyntaxFormattingOptions.Default.PreferTopLevelStatements); -#if false - - public static readonly Option2> VarElsewhere = CreateOption( - CSharpCodeStyleOptionGroups.VarPreferences, nameof(VarElsewhere), - defaultValue: s_trueWithSuggestionEnforcement, - "csharp_style_var_elsewhere", - "TextEditor.CSharp.Specific.UseImplicitTypeWherePossible"); - -#endif - - static CSharpCodeStyleOptions() - { - // Note that the static constructor executes after all the static field initializers for the options have executed, - // and each field initializer adds the created option to s_allOptionsBuilder. - AllOptions = s_allOptionsBuilder.ToImmutable(); - } - - public static IEnumerable>> GetCodeStyleOptions() - { - yield return VarForBuiltInTypes; - yield return VarWhenTypeIsApparent; - yield return VarElsewhere; - yield return PreferConditionalDelegateCall; - yield return PreferSwitchExpression; - yield return PreferPatternMatching; - yield return PreferPatternMatchingOverAsWithNullCheck; - yield return PreferPatternMatchingOverIsWithCastCheck; - yield return PreferSimpleDefaultExpression; - yield return PreferLocalOverAnonymousFunction; - yield return PreferThrowExpression; - yield return PreferInlinedVariableDeclaration; - yield return PreferDeconstructedVariableDeclaration; - yield return PreferIndexOperator; - yield return PreferRangeOperator; - yield return AllowEmbeddedStatementsOnSameLine; - yield return AllowBlankLinesBetweenConsecutiveBraces; - yield return AllowBlankLineAfterColonInConstructorInitializer; - yield return AllowBlankLineAfterTokenInConditionalExpression; - yield return AllowBlankLineAfterTokenInArrowExpressionClause; - } - - public static IEnumerable>> GetExpressionBodyOptions() - { - yield return PreferExpressionBodiedConstructors; - yield return PreferExpressionBodiedMethods; - yield return PreferExpressionBodiedOperators; - yield return PreferExpressionBodiedProperties; - yield return PreferExpressionBodiedIndexers; - yield return PreferExpressionBodiedAccessors; - yield return PreferExpressionBodiedLambdas; - } + internal static readonly ImmutableArray AllOptions = s_allOptionsBuilder.ToImmutable(); } internal static class CSharpCodeStyleOptionGroups { - public static readonly OptionGroup VarPreferences = new(CSharpCompilerExtensionsResources.var_preferences, priority: 1); - public static readonly OptionGroup ExpressionBodiedMembers = new(CSharpCompilerExtensionsResources.Expression_bodied_members, priority: 2); - public static readonly OptionGroup PatternMatching = new(CSharpCompilerExtensionsResources.Pattern_matching_preferences, priority: 3); - public static readonly OptionGroup NullCheckingPreferences = new(CSharpCompilerExtensionsResources.Null_checking_preferences, priority: 4); - public static readonly OptionGroup Modifier = new(CompilerExtensionsResources.Modifier_preferences, priority: 5); - public static readonly OptionGroup CodeBlockPreferences = new(CSharpCompilerExtensionsResources.Code_block_preferences, priority: 6); - public static readonly OptionGroup ExpressionLevelPreferences = new(CompilerExtensionsResources.Expression_level_preferences, priority: 7); - public static readonly OptionGroup UsingDirectivePreferences = new(CSharpCompilerExtensionsResources.using_directive_preferences, priority: 8); - public static readonly OptionGroup NewLinePreferences = new(CompilerExtensionsResources.New_line_preferences, priority: 9); + public static readonly OptionGroup VarPreferences = new(CSharpCompilerExtensionsResources.var_preferences, priority: 1, parent: CodeStyleOptionGroups.CodeStyle); + public static readonly OptionGroup ExpressionBodiedMembers = new(CSharpCompilerExtensionsResources.Expression_bodied_members, priority: 2, parent: CodeStyleOptionGroups.CodeStyle); + public static readonly OptionGroup PatternMatching = new(CSharpCompilerExtensionsResources.Pattern_matching_preferences, priority: 3, parent: CodeStyleOptionGroups.CodeStyle); + public static readonly OptionGroup NullCheckingPreferences = new(CSharpCompilerExtensionsResources.Null_checking_preferences, priority: 4, parent: CodeStyleOptionGroups.CodeStyle); + public static readonly OptionGroup Modifier = new(CompilerExtensionsResources.Modifier_preferences, priority: 5, parent: CodeStyleOptionGroups.CodeStyle); + public static readonly OptionGroup CodeBlockPreferences = new(CSharpCompilerExtensionsResources.Code_block_preferences, priority: 6, parent: CodeStyleOptionGroups.CodeStyle); + public static readonly OptionGroup ExpressionLevelPreferences = new(CompilerExtensionsResources.Expression_level_preferences, priority: 7, parent: CodeStyleOptionGroups.CodeStyle); + public static readonly OptionGroup UsingDirectivePreferences = new(CSharpCompilerExtensionsResources.using_directive_preferences, priority: 8, parent: CodeStyleOptionGroups.CodeStyle); + public static readonly OptionGroup NewLinePreferences = new(CompilerExtensionsResources.New_line_preferences, priority: 9, parent: CodeStyleOptionGroups.CodeStyle); } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/CSharpFormattingOptions2.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/CSharpFormattingOptions2.cs index 3c9384aa28fb0..562faceb5448e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/CSharpFormattingOptions2.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/CSharpFormattingOptions2.cs @@ -16,6 +16,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Formatting { internal static partial class CSharpFormattingOptions2 { + private const string PublicFeatureName = "CSharpFormattingOptions"; + private static readonly ImmutableArray.Builder s_allOptionsBuilder = ImmutableArray.CreateBuilder(); // Maps to store mapping between special option kinds and the corresponding editor config string representations. @@ -64,358 +66,212 @@ internal static partial class CSharpFormattingOptions2 internal static ImmutableArray AllOptions { get; } - private static Option2 CreateOption( - OptionGroup group, string name, T defaultValue, - OptionStorageLocation2 storageLocation1) - { - var option = new Option2( - "CSharpFormattingOptions", - group, name, defaultValue, - ImmutableArray.Create(storageLocation1), LanguageNames.CSharp); - - s_allOptionsBuilder.Add(option); - return option; - } - - private static Option2 CreateOption( - OptionGroup group, string name, T defaultValue, - OptionStorageLocation2 storageLocation1, - OptionStorageLocation2 storageLocation2) + private static Option2 CreateOption(OptionGroup group, string name, T defaultValue, EditorConfigValueSerializer? serializer = null) { - var option = new Option2( - "CSharpFormattingOptions", - group, name, defaultValue, - ImmutableArray.Create(storageLocation1, storageLocation2), LanguageNames.CSharp); - + var option = new Option2(name, defaultValue, group, LanguageNames.CSharp, isEditorConfigOption: true, serializer: serializer); s_allOptionsBuilder.Add(option); return option; } - private static Option2 CreateNewLineForBracesLegacyOption(string name, bool defaultValue) - => new( - feature: "CSharpFormattingOptions", - CSharpFormattingOptionGroups.NewLine, - name, - defaultValue, - new RoamingProfileStorageLocation($"TextEditor.CSharp.Specific.{name}")); - public static Option2 SpacingAfterMethodDeclarationName { get; } = CreateOption( - CSharpFormattingOptionGroups.Spacing, nameof(SpacingAfterMethodDeclarationName), - CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.AfterMethodDeclarationName), - EditorConfigStorageLocation.ForBoolOption("csharp_space_between_method_declaration_name_and_open_parenthesis"), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.SpacingAfterMethodDeclarationName")); + CSharpFormattingOptionGroups.Spacing, "csharp_space_between_method_declaration_name_and_open_parenthesis", + CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.AfterMethodDeclarationName)) + .WithPublicOption(PublicFeatureName, "SpacingAfterMethodDeclarationName"); public static Option2 SpaceWithinMethodDeclarationParenthesis { get; } = CreateOption( - CSharpFormattingOptionGroups.Spacing, nameof(SpaceWithinMethodDeclarationParenthesis), - CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.WithinMethodDeclarationParenthesis), - EditorConfigStorageLocation.ForBoolOption("csharp_space_between_method_declaration_parameter_list_parentheses"), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.SpaceWithinMethodDeclarationParenthesis")); + CSharpFormattingOptionGroups.Spacing, "csharp_space_between_method_declaration_parameter_list_parentheses", + CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.WithinMethodDeclarationParenthesis)) + .WithPublicOption(PublicFeatureName, "SpaceWithinMethodDeclarationParenthesis"); public static Option2 SpaceBetweenEmptyMethodDeclarationParentheses { get; } = CreateOption( - CSharpFormattingOptionGroups.Spacing, nameof(SpaceBetweenEmptyMethodDeclarationParentheses), - CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.BetweenEmptyMethodDeclarationParentheses), - EditorConfigStorageLocation.ForBoolOption("csharp_space_between_method_declaration_empty_parameter_list_parentheses"), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.SpaceBetweenEmptyMethodDeclarationParentheses")); + CSharpFormattingOptionGroups.Spacing, "csharp_space_between_method_declaration_empty_parameter_list_parentheses", + CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.BetweenEmptyMethodDeclarationParentheses)) + .WithPublicOption(PublicFeatureName, "SpaceBetweenEmptyMethodDeclarationParentheses"); public static Option2 SpaceAfterMethodCallName { get; } = CreateOption( - CSharpFormattingOptionGroups.Spacing, nameof(SpaceAfterMethodCallName), - CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.AfterMethodCallName), - EditorConfigStorageLocation.ForBoolOption("csharp_space_between_method_call_name_and_opening_parenthesis"), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.SpaceAfterMethodCallName")); + CSharpFormattingOptionGroups.Spacing, "csharp_space_between_method_call_name_and_opening_parenthesis", + CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.AfterMethodCallName)) + .WithPublicOption(PublicFeatureName, "SpaceAfterMethodCallName"); public static Option2 SpaceWithinMethodCallParentheses { get; } = CreateOption( - CSharpFormattingOptionGroups.Spacing, nameof(SpaceWithinMethodCallParentheses), - CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.WithinMethodCallParentheses), - EditorConfigStorageLocation.ForBoolOption("csharp_space_between_method_call_parameter_list_parentheses"), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.SpaceWithinMethodCallParentheses")); + CSharpFormattingOptionGroups.Spacing, "csharp_space_between_method_call_parameter_list_parentheses", + CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.WithinMethodCallParentheses)) + .WithPublicOption(PublicFeatureName, "SpaceWithinMethodCallParentheses"); public static Option2 SpaceBetweenEmptyMethodCallParentheses { get; } = CreateOption( - CSharpFormattingOptionGroups.Spacing, nameof(SpaceBetweenEmptyMethodCallParentheses), - CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.BetweenEmptyMethodCallParentheses), - EditorConfigStorageLocation.ForBoolOption("csharp_space_between_method_call_empty_parameter_list_parentheses"), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.SpaceBetweenEmptyMethodCallParentheses")); + CSharpFormattingOptionGroups.Spacing, "csharp_space_between_method_call_empty_parameter_list_parentheses", + CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.BetweenEmptyMethodCallParentheses)) + .WithPublicOption(PublicFeatureName, "SpaceBetweenEmptyMethodCallParentheses"); public static Option2 SpaceAfterControlFlowStatementKeyword { get; } = CreateOption( - CSharpFormattingOptionGroups.Spacing, nameof(SpaceAfterControlFlowStatementKeyword), - CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.AfterControlFlowStatementKeyword), - EditorConfigStorageLocation.ForBoolOption("csharp_space_after_keywords_in_control_flow_statements"), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.SpaceAfterControlFlowStatementKeyword")); - - // Legacy options, only to be used in OptionSets and global options. - - public static Option2 SpaceWithinExpressionParentheses { get; } = new Option2( - feature: "CSharpFormattingOptions", - CSharpFormattingOptionGroups.Spacing, - name: "SpaceWithinExpressionParentheses", - defaultValue: CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.WithinExpressionParentheses), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.SpaceWithinExpressionParentheses")); - - public static Option2 SpaceWithinCastParentheses { get; } = new Option2( - feature: "CSharpFormattingOptions", - CSharpFormattingOptionGroups.Spacing, - name: "SpaceWithinCastParentheses", - defaultValue: CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.WithinCastParentheses), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.SpaceWithinCastParentheses")); + CSharpFormattingOptionGroups.Spacing, "csharp_space_after_keywords_in_control_flow_statements", + CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.AfterControlFlowStatementKeyword)) + .WithPublicOption(PublicFeatureName, "SpaceAfterControlFlowStatementKeyword"); - public static Option2 SpaceWithinOtherParentheses { get; } = new Option2( - feature: "CSharpFormattingOptions", - CSharpFormattingOptionGroups.Spacing, - name: "SpaceWithinOtherParentheses", - defaultValue: CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.WithinOtherParentheses), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.SpaceWithinOtherParentheses")); - - // editor config option: public static Option2 SpaceBetweenParentheses { get; } = CreateOption( CSharpFormattingOptionGroups.Spacing, name: "csharp_space_between_parentheses", CSharpSyntaxFormattingOptions.SpacingDefault.ToSpacingWithinParentheses(), - new EditorConfigStorageLocation( - "csharp_space_between_parentheses", + new EditorConfigValueSerializer( parseValue: list => ParseSpacingWithinParenthesesList(list), -#if !CODE_STYLE - getValueFromOptionSet: set => - (set.GetOption(SpaceWithinExpressionParentheses) ? SpacePlacementWithinParentheses.Expressions : 0) | - (set.GetOption(SpaceWithinCastParentheses) ? SpacePlacementWithinParentheses.TypeCasts : 0) | - (set.GetOption(SpaceWithinOtherParentheses) ? SpacePlacementWithinParentheses.ControlFlowStatements : 0), -#endif serializeValue: ToEditorConfigValue)); public static Option2 SpaceAfterCast { get; } = CreateOption( - CSharpFormattingOptionGroups.Spacing, nameof(SpaceAfterCast), - CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.AfterCast), - EditorConfigStorageLocation.ForBoolOption("csharp_space_after_cast"), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.SpaceAfterCast")); + CSharpFormattingOptionGroups.Spacing, "csharp_space_after_cast", + CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.AfterCast)) + .WithPublicOption(PublicFeatureName, "SpaceAfterCast"); public static Option2 SpacesIgnoreAroundVariableDeclaration { get; } = CreateOption( - CSharpFormattingOptionGroups.Spacing, nameof(SpacesIgnoreAroundVariableDeclaration), + CSharpFormattingOptionGroups.Spacing, "csharp_space_around_declaration_statements", CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.IgnoreAroundVariableDeclaration), - new EditorConfigStorageLocation( - "csharp_space_around_declaration_statements", + new EditorConfigValueSerializer( s => DetermineIfIgnoreSpacesAroundVariableDeclarationIsSet(s), - v => v ? "ignore" : "false"), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.SpacesIgnoreAroundVariableDeclaration")); + v => v ? "ignore" : "false")) + .WithPublicOption(PublicFeatureName, "SpacesIgnoreAroundVariableDeclaration"); public static Option2 SpaceBeforeOpenSquareBracket { get; } = CreateOption( - CSharpFormattingOptionGroups.Spacing, nameof(SpaceBeforeOpenSquareBracket), - CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.BeforeOpenSquareBracket), - EditorConfigStorageLocation.ForBoolOption("csharp_space_before_open_square_brackets"), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.SpaceBeforeOpenSquareBracket")); + CSharpFormattingOptionGroups.Spacing, "csharp_space_before_open_square_brackets", + CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.BeforeOpenSquareBracket)) + .WithPublicOption(PublicFeatureName, "SpaceBeforeOpenSquareBracket"); public static Option2 SpaceBetweenEmptySquareBrackets { get; } = CreateOption( - CSharpFormattingOptionGroups.Spacing, nameof(SpaceBetweenEmptySquareBrackets), - CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.BetweenEmptySquareBrackets), - EditorConfigStorageLocation.ForBoolOption("csharp_space_between_empty_square_brackets"), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.SpaceBetweenEmptySquareBrackets")); + CSharpFormattingOptionGroups.Spacing, "csharp_space_between_empty_square_brackets", + CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.BetweenEmptySquareBrackets)) + .WithPublicOption(PublicFeatureName, "SpaceBetweenEmptySquareBrackets"); public static Option2 SpaceWithinSquareBrackets { get; } = CreateOption( - CSharpFormattingOptionGroups.Spacing, nameof(SpaceWithinSquareBrackets), - CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.WithinSquareBrackets), - EditorConfigStorageLocation.ForBoolOption("csharp_space_between_square_brackets"), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.SpaceWithinSquareBrackets")); + CSharpFormattingOptionGroups.Spacing, "csharp_space_between_square_brackets", + CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.WithinSquareBrackets)) + .WithPublicOption(PublicFeatureName, "SpaceWithinSquareBrackets"); public static Option2 SpaceAfterColonInBaseTypeDeclaration { get; } = CreateOption( - CSharpFormattingOptionGroups.Spacing, nameof(SpaceAfterColonInBaseTypeDeclaration), - CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.AfterColonInBaseTypeDeclaration), - EditorConfigStorageLocation.ForBoolOption("csharp_space_after_colon_in_inheritance_clause"), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.SpaceAfterColonInBaseTypeDeclaration")); + CSharpFormattingOptionGroups.Spacing, "csharp_space_after_colon_in_inheritance_clause", + CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.AfterColonInBaseTypeDeclaration)) + .WithPublicOption(PublicFeatureName, "SpaceAfterColonInBaseTypeDeclaration"); public static Option2 SpaceAfterComma { get; } = CreateOption( - CSharpFormattingOptionGroups.Spacing, nameof(SpaceAfterComma), - CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.AfterComma), - EditorConfigStorageLocation.ForBoolOption("csharp_space_after_comma"), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.SpaceAfterComma")); + CSharpFormattingOptionGroups.Spacing, "csharp_space_after_comma", + CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.AfterComma)) + .WithPublicOption(PublicFeatureName, "SpaceAfterComma"); public static Option2 SpaceAfterDot { get; } = CreateOption( - CSharpFormattingOptionGroups.Spacing, nameof(SpaceAfterDot), - CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.AfterDot), - EditorConfigStorageLocation.ForBoolOption("csharp_space_after_dot"), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.SpaceAfterDot")); + CSharpFormattingOptionGroups.Spacing, "csharp_space_after_dot", + CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.AfterDot)) + .WithPublicOption(PublicFeatureName, "SpaceAfterDot"); public static Option2 SpaceAfterSemicolonsInForStatement { get; } = CreateOption( - CSharpFormattingOptionGroups.Spacing, nameof(SpaceAfterSemicolonsInForStatement), - CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.AfterSemicolonsInForStatement), - EditorConfigStorageLocation.ForBoolOption("csharp_space_after_semicolon_in_for_statement"), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.SpaceAfterSemicolonsInForStatement")); + CSharpFormattingOptionGroups.Spacing, "csharp_space_after_semicolon_in_for_statement", + CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.AfterSemicolonsInForStatement)) + .WithPublicOption(PublicFeatureName, "SpaceAfterSemicolonsInForStatement"); public static Option2 SpaceBeforeColonInBaseTypeDeclaration { get; } = CreateOption( - CSharpFormattingOptionGroups.Spacing, nameof(SpaceBeforeColonInBaseTypeDeclaration), - CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.BeforeColonInBaseTypeDeclaration), - EditorConfigStorageLocation.ForBoolOption("csharp_space_before_colon_in_inheritance_clause"), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.SpaceBeforeColonInBaseTypeDeclaration")); + CSharpFormattingOptionGroups.Spacing, "csharp_space_before_colon_in_inheritance_clause", + CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.BeforeColonInBaseTypeDeclaration)) + .WithPublicOption(PublicFeatureName, "SpaceBeforeColonInBaseTypeDeclaration"); public static Option2 SpaceBeforeComma { get; } = CreateOption( - CSharpFormattingOptionGroups.Spacing, nameof(SpaceBeforeComma), - CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.BeforeComma), - EditorConfigStorageLocation.ForBoolOption("csharp_space_before_comma"), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.SpaceBeforeComma")); + CSharpFormattingOptionGroups.Spacing, "csharp_space_before_comma", + CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.BeforeComma)) + .WithPublicOption(PublicFeatureName, "SpaceBeforeComma"); public static Option2 SpaceBeforeDot { get; } = CreateOption( - CSharpFormattingOptionGroups.Spacing, nameof(SpaceBeforeDot), - CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.BeforeDot), - EditorConfigStorageLocation.ForBoolOption("csharp_space_before_dot"), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.SpaceBeforeDot")); + CSharpFormattingOptionGroups.Spacing, "csharp_space_before_dot", + CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.BeforeDot)) + .WithPublicOption(PublicFeatureName, "SpaceBeforeDot"); public static Option2 SpaceBeforeSemicolonsInForStatement { get; } = CreateOption( - CSharpFormattingOptionGroups.Spacing, nameof(SpaceBeforeSemicolonsInForStatement), - CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.BeforeSemicolonsInForStatement), - EditorConfigStorageLocation.ForBoolOption("csharp_space_before_semicolon_in_for_statement"), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.SpaceBeforeSemicolonsInForStatement")); + CSharpFormattingOptionGroups.Spacing, "csharp_space_before_semicolon_in_for_statement", + CSharpSyntaxFormattingOptions.SpacingDefault.HasFlag(SpacePlacement.BeforeSemicolonsInForStatement)) + .WithPublicOption(PublicFeatureName, "SpaceBeforeSemicolonsInForStatement"); public static Option2 SpacingAroundBinaryOperator { get; } = CreateOption( - CSharpFormattingOptionGroups.Spacing, nameof(SpacingAroundBinaryOperator), + CSharpFormattingOptionGroups.Spacing, "csharp_space_around_binary_operators", CSharpSyntaxFormattingOptions.Default.SpacingAroundBinaryOperator, - new EditorConfigStorageLocation( - "csharp_space_around_binary_operators", + new EditorConfigValueSerializer( s => ParseEditorConfigSpacingAroundBinaryOperator(s), - GetSpacingAroundBinaryOperatorEditorConfigString), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.SpacingAroundBinaryOperator")); + GetSpacingAroundBinaryOperatorEditorConfigString)) + .WithPublicOption(PublicFeatureName, "SpacingAroundBinaryOperator"); public static Option2 IndentBraces { get; } = CreateOption( - CSharpFormattingOptionGroups.Indentation, nameof(IndentBraces), - CSharpSyntaxFormattingOptions.IndentationDefault.HasFlag(IndentationPlacement.Braces), - EditorConfigStorageLocation.ForBoolOption("csharp_indent_braces"), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.OpenCloseBracesIndent")); + CSharpFormattingOptionGroups.Indentation, "csharp_indent_braces", + CSharpSyntaxFormattingOptions.IndentationDefault.HasFlag(IndentationPlacement.Braces)) + .WithPublicOption(PublicFeatureName, "IndentBraces"); public static Option2 IndentBlock { get; } = CreateOption( - CSharpFormattingOptionGroups.Indentation, nameof(IndentBlock), - CSharpSyntaxFormattingOptions.IndentationDefault.HasFlag(IndentationPlacement.BlockContents), - EditorConfigStorageLocation.ForBoolOption("csharp_indent_block_contents"), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.IndentBlock")); + CSharpFormattingOptionGroups.Indentation, "csharp_indent_block_contents", + CSharpSyntaxFormattingOptions.IndentationDefault.HasFlag(IndentationPlacement.BlockContents)) + .WithPublicOption(PublicFeatureName, "IndentBlock"); public static Option2 IndentSwitchSection { get; } = CreateOption( - CSharpFormattingOptionGroups.Indentation, nameof(IndentSwitchSection), - CSharpSyntaxFormattingOptions.IndentationDefault.HasFlag(IndentationPlacement.SwitchSection), - EditorConfigStorageLocation.ForBoolOption("csharp_indent_switch_labels"), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.IndentSwitchSection")); + CSharpFormattingOptionGroups.Indentation, "csharp_indent_switch_labels", + CSharpSyntaxFormattingOptions.IndentationDefault.HasFlag(IndentationPlacement.SwitchSection)) + .WithPublicOption(PublicFeatureName, "IndentSwitchSection"); public static Option2 IndentSwitchCaseSection { get; } = CreateOption( - CSharpFormattingOptionGroups.Indentation, nameof(IndentSwitchCaseSection), - CSharpSyntaxFormattingOptions.IndentationDefault.HasFlag(IndentationPlacement.SwitchSection), - EditorConfigStorageLocation.ForBoolOption("csharp_indent_case_contents"), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.IndentSwitchCaseSection")); + CSharpFormattingOptionGroups.Indentation, "csharp_indent_case_contents", + CSharpSyntaxFormattingOptions.IndentationDefault.HasFlag(IndentationPlacement.SwitchSection)) + .WithPublicOption(PublicFeatureName, "IndentSwitchCaseSection"); public static Option2 IndentSwitchCaseSectionWhenBlock { get; } = CreateOption( - CSharpFormattingOptionGroups.Indentation, nameof(IndentSwitchCaseSectionWhenBlock), - CSharpSyntaxFormattingOptions.IndentationDefault.HasFlag(IndentationPlacement.SwitchCaseContentsWhenBlock), - EditorConfigStorageLocation.ForBoolOption("csharp_indent_case_contents_when_block"), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.IndentSwitchCaseSectionWhenBlock")); + CSharpFormattingOptionGroups.Indentation, "csharp_indent_case_contents_when_block", + CSharpSyntaxFormattingOptions.IndentationDefault.HasFlag(IndentationPlacement.SwitchCaseContentsWhenBlock)) + .WithPublicOption(PublicFeatureName, "IndentSwitchCaseSectionWhenBlock"); public static Option2 LabelPositioning { get; } = CreateOption( - CSharpFormattingOptionGroups.Indentation, nameof(LabelPositioning), + CSharpFormattingOptionGroups.Indentation, "csharp_indent_labels", CSharpSyntaxFormattingOptions.Default.LabelPositioning, - new EditorConfigStorageLocation( - "csharp_indent_labels", + new EditorConfigValueSerializer( s => ParseEditorConfigLabelPositioning(s), - GetLabelPositionOptionEditorConfigString), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.LabelPositioning")); + GetLabelPositionOptionEditorConfigString)) + .WithPublicOption(PublicFeatureName, "LabelPositioning"); public static Option2 WrappingPreserveSingleLine { get; } = CreateOption( - CSharpFormattingOptionGroups.Wrapping, nameof(WrappingPreserveSingleLine), - CSharpSyntaxFormattingOptions.Default.WrappingPreserveSingleLine, - EditorConfigStorageLocation.ForBoolOption("csharp_preserve_single_line_blocks"), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.WrappingPreserveSingleLine")); + CSharpFormattingOptionGroups.Wrapping, "csharp_preserve_single_line_blocks", + CSharpSyntaxFormattingOptions.Default.WrappingPreserveSingleLine) + .WithPublicOption(PublicFeatureName, "WrappingPreserveSingleLine"); public static Option2 WrappingKeepStatementsOnSingleLine { get; } = CreateOption( - CSharpFormattingOptionGroups.Wrapping, nameof(WrappingKeepStatementsOnSingleLine), - CSharpSyntaxFormattingOptions.Default.WrappingKeepStatementsOnSingleLine, - EditorConfigStorageLocation.ForBoolOption("csharp_preserve_single_line_statements"), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.WrappingKeepStatementsOnSingleLine")); - - // Legacy options, only to be used in OptionSets and global options. - - public static Option2 NewLinesForBracesInTypes { get; } = CreateNewLineForBracesLegacyOption( - "NewLinesForBracesInTypes", - CSharpSyntaxFormattingOptions.NewLinesDefault.HasFlag(NewLinePlacement.BeforeOpenBraceInTypes)); - - public static Option2 NewLinesForBracesInMethods { get; } = CreateNewLineForBracesLegacyOption( - "NewLinesForBracesInMethods", - CSharpSyntaxFormattingOptions.NewLinesDefault.HasFlag(NewLinePlacement.BeforeOpenBraceInMethods)); - - public static Option2 NewLinesForBracesInProperties { get; } = CreateNewLineForBracesLegacyOption( - "NewLinesForBracesInProperties", - CSharpSyntaxFormattingOptions.NewLinesDefault.HasFlag(NewLinePlacement.BeforeOpenBraceInProperties)); + CSharpFormattingOptionGroups.Wrapping, "csharp_preserve_single_line_statements", + CSharpSyntaxFormattingOptions.Default.WrappingKeepStatementsOnSingleLine) + .WithPublicOption(PublicFeatureName, "WrappingKeepStatementsOnSingleLine"); - public static Option2 NewLinesForBracesInAccessors { get; } = CreateNewLineForBracesLegacyOption( - "NewLinesForBracesInAccessors", - CSharpSyntaxFormattingOptions.NewLinesDefault.HasFlag(NewLinePlacement.BeforeOpenBraceInAccessors)); - - public static Option2 NewLinesForBracesInAnonymousMethods { get; } = CreateNewLineForBracesLegacyOption( - "NewLinesForBracesInAnonymousMethods", - CSharpSyntaxFormattingOptions.NewLinesDefault.HasFlag(NewLinePlacement.BeforeOpenBraceInAnonymousMethods)); - - public static Option2 NewLinesForBracesInControlBlocks { get; } = CreateNewLineForBracesLegacyOption( - "NewLinesForBracesInControlBlocks", - CSharpSyntaxFormattingOptions.NewLinesDefault.HasFlag(NewLinePlacement.BeforeOpenBraceInControlBlocks)); - - public static Option2 NewLinesForBracesInAnonymousTypes { get; } = CreateNewLineForBracesLegacyOption( - "NewLinesForBracesInAnonymousTypes", - CSharpSyntaxFormattingOptions.NewLinesDefault.HasFlag(NewLinePlacement.BeforeOpenBraceInAnonymousTypes)); - - public static Option2 NewLinesForBracesInObjectCollectionArrayInitializers { get; } = CreateNewLineForBracesLegacyOption( - "NewLinesForBracesInObjectCollectionArrayInitializers", - CSharpSyntaxFormattingOptions.NewLinesDefault.HasFlag(NewLinePlacement.BeforeOpenBraceInObjectCollectionArrayInitializers)); - - public static Option2 NewLinesForBracesInLambdaExpressionBody { get; } = CreateNewLineForBracesLegacyOption( - "NewLinesForBracesInLambdaExpressionBody", - CSharpSyntaxFormattingOptions.NewLinesDefault.HasFlag(NewLinePlacement.BeforeOpenBraceInLambdaExpressionBody)); - - // editor config option: public static Option2 NewLineBeforeOpenBrace { get; } = CreateOption( CSharpFormattingOptionGroups.NewLine, name: "csharp_new_line_before_open_brace", CSharpSyntaxFormattingOptions.NewLinesDefault.ToNewLineBeforeOpenBracePlacement(), - new EditorConfigStorageLocation( - "csharp_new_line_before_open_brace", + new EditorConfigValueSerializer( parseValue: list => ParseNewLineBeforeOpenBracePlacementList(list), -#if !CODE_STYLE - getValueFromOptionSet: set => - (set.GetOption(NewLinesForBracesInTypes) ? NewLineBeforeOpenBracePlacement.Types : 0) | - (set.GetOption(NewLinesForBracesInAnonymousTypes) ? NewLineBeforeOpenBracePlacement.AnonymousTypes : 0) | - (set.GetOption(NewLinesForBracesInObjectCollectionArrayInitializers) ? NewLineBeforeOpenBracePlacement.ObjectCollectionArrayInitializers : 0) | - (set.GetOption(NewLinesForBracesInProperties) ? NewLineBeforeOpenBracePlacement.Properties : 0) | - (set.GetOption(NewLinesForBracesInMethods) ? NewLineBeforeOpenBracePlacement.Methods : 0) | - (set.GetOption(NewLinesForBracesInAccessors) ? NewLineBeforeOpenBracePlacement.Accessors : 0) | - (set.GetOption(NewLinesForBracesInAnonymousMethods) ? NewLineBeforeOpenBracePlacement.AnonymousMethods : 0) | - (set.GetOption(NewLinesForBracesInLambdaExpressionBody) ? NewLineBeforeOpenBracePlacement.LambdaExpressionBody : 0) | - (set.GetOption(NewLinesForBracesInControlBlocks) ? NewLineBeforeOpenBracePlacement.ControlBlocks : 0), -#endif serializeValue: ToEditorConfigValue)); public static Option2 NewLineForElse { get; } = CreateOption( - CSharpFormattingOptionGroups.NewLine, nameof(NewLineForElse), - CSharpSyntaxFormattingOptions.NewLinesDefault.HasFlag(NewLinePlacement.BeforeElse), - EditorConfigStorageLocation.ForBoolOption("csharp_new_line_before_else"), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.NewLineForElse")); + CSharpFormattingOptionGroups.NewLine, "csharp_new_line_before_else", + CSharpSyntaxFormattingOptions.NewLinesDefault.HasFlag(NewLinePlacement.BeforeElse)) + .WithPublicOption(PublicFeatureName, "NewLineForElse"); public static Option2 NewLineForCatch { get; } = CreateOption( - CSharpFormattingOptionGroups.NewLine, nameof(NewLineForCatch), - CSharpSyntaxFormattingOptions.NewLinesDefault.HasFlag(NewLinePlacement.BeforeCatch), - EditorConfigStorageLocation.ForBoolOption("csharp_new_line_before_catch"), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.NewLineForCatch")); + CSharpFormattingOptionGroups.NewLine, "csharp_new_line_before_catch", + CSharpSyntaxFormattingOptions.NewLinesDefault.HasFlag(NewLinePlacement.BeforeCatch)) + .WithPublicOption(PublicFeatureName, "NewLineForCatch"); public static Option2 NewLineForFinally { get; } = CreateOption( - CSharpFormattingOptionGroups.NewLine, nameof(NewLineForFinally), - CSharpSyntaxFormattingOptions.NewLinesDefault.HasFlag(NewLinePlacement.BeforeFinally), - EditorConfigStorageLocation.ForBoolOption("csharp_new_line_before_finally"), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.NewLineForFinally")); + CSharpFormattingOptionGroups.NewLine, "csharp_new_line_before_finally", + CSharpSyntaxFormattingOptions.NewLinesDefault.HasFlag(NewLinePlacement.BeforeFinally)) + .WithPublicOption(PublicFeatureName, "NewLineForFinally"); public static Option2 NewLineForMembersInObjectInit { get; } = CreateOption( - CSharpFormattingOptionGroups.NewLine, nameof(NewLineForMembersInObjectInit), - CSharpSyntaxFormattingOptions.NewLinesDefault.HasFlag(NewLinePlacement.BeforeMembersInObjectInitializers), - EditorConfigStorageLocation.ForBoolOption("csharp_new_line_before_members_in_object_initializers"), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.NewLineForMembersInObjectInit")); + CSharpFormattingOptionGroups.NewLine, "csharp_new_line_before_members_in_object_initializers", + CSharpSyntaxFormattingOptions.NewLinesDefault.HasFlag(NewLinePlacement.BeforeMembersInObjectInitializers)) + .WithPublicOption(PublicFeatureName, "NewLineForMembersInObjectInit"); public static Option2 NewLineForMembersInAnonymousTypes { get; } = CreateOption( - CSharpFormattingOptionGroups.NewLine, nameof(NewLineForMembersInAnonymousTypes), - CSharpSyntaxFormattingOptions.NewLinesDefault.HasFlag(NewLinePlacement.BeforeMembersInAnonymousTypes), - EditorConfigStorageLocation.ForBoolOption("csharp_new_line_before_members_in_anonymous_types"), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.NewLineForMembersInAnonymousTypes")); + CSharpFormattingOptionGroups.NewLine, "csharp_new_line_before_members_in_anonymous_types", + CSharpSyntaxFormattingOptions.NewLinesDefault.HasFlag(NewLinePlacement.BeforeMembersInAnonymousTypes)) + .WithPublicOption(PublicFeatureName, "NewLineForMembersInAnonymousTypes"); public static Option2 NewLineForClausesInQuery { get; } = CreateOption( - CSharpFormattingOptionGroups.NewLine, nameof(NewLineForClausesInQuery), - CSharpSyntaxFormattingOptions.NewLinesDefault.HasFlag(NewLinePlacement.BetweenQueryExpressionClauses), - EditorConfigStorageLocation.ForBoolOption("csharp_new_line_between_query_expression_clauses"), - new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.NewLineForClausesInQuery")); + CSharpFormattingOptionGroups.NewLine, "csharp_new_line_between_query_expression_clauses", + CSharpSyntaxFormattingOptions.NewLinesDefault.HasFlag(NewLinePlacement.BetweenQueryExpressionClauses)) + .WithPublicOption(PublicFeatureName, "NewLineForClausesInQuery"); static CSharpFormattingOptions2() { diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/CSharpSyntaxFormatting.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/CSharpSyntaxFormatting.cs index a5148d642f996..75577e6ac1b1e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/CSharpSyntaxFormatting.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/CSharpSyntaxFormatting.cs @@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.CSharp.Formatting { @@ -38,7 +39,7 @@ public override ImmutableArray GetDefaultFormattingRules public override SyntaxFormattingOptions DefaultOptions => CSharpSyntaxFormattingOptions.Default; - public override SyntaxFormattingOptions GetFormattingOptions(AnalyzerConfigOptions options, SyntaxFormattingOptions? fallbackOptions) + public override SyntaxFormattingOptions GetFormattingOptions(IOptionsReader options, SyntaxFormattingOptions? fallbackOptions) => options.GetCSharpSyntaxFormattingOptions((CSharpSyntaxFormattingOptions?)fallbackOptions); protected override IFormattingResult CreateAggregatedFormattingResult(SyntaxNode node, IList results, SimpleIntervalTree? formattingSpans = null) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/CSharpSyntaxFormattingOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/CSharpSyntaxFormattingOptions.cs index d1d9123cb8e5f..1bbe37723d70f 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/CSharpSyntaxFormattingOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/CSharpSyntaxFormattingOptions.cs @@ -3,13 +3,11 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; using System.Runtime.Serialization; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.CodeStyle; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Options; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Formatting @@ -167,55 +165,55 @@ public override int GetHashCode() internal static class CSharpSyntaxFormattingOptionsProviders { - public static CSharpSyntaxFormattingOptions GetCSharpSyntaxFormattingOptions(this AnalyzerConfigOptions options, CSharpSyntaxFormattingOptions? fallbackOptions) + public static CSharpSyntaxFormattingOptions GetCSharpSyntaxFormattingOptions(this IOptionsReader options, CSharpSyntaxFormattingOptions? fallbackOptions) { fallbackOptions ??= CSharpSyntaxFormattingOptions.Default; return new() { - Common = options.GetCommonSyntaxFormattingOptions(fallbackOptions.Common), + Common = options.GetCommonSyntaxFormattingOptions(LanguageNames.CSharp, fallbackOptions.Common), Spacing = - (options.GetEditorConfigOption(CSharpFormattingOptions2.SpacesIgnoreAroundVariableDeclaration, fallbackOptions.Spacing.HasFlag(SpacePlacement.IgnoreAroundVariableDeclaration)) ? SpacePlacement.IgnoreAroundVariableDeclaration : 0) | - (options.GetEditorConfigOption(CSharpFormattingOptions2.SpacingAfterMethodDeclarationName, fallbackOptions.Spacing.HasFlag(SpacePlacement.AfterMethodDeclarationName)) ? SpacePlacement.AfterMethodDeclarationName : 0) | - (options.GetEditorConfigOption(CSharpFormattingOptions2.SpaceBetweenEmptyMethodDeclarationParentheses, fallbackOptions.Spacing.HasFlag(SpacePlacement.BetweenEmptyMethodDeclarationParentheses)) ? SpacePlacement.BetweenEmptyMethodDeclarationParentheses : 0) | - (options.GetEditorConfigOption(CSharpFormattingOptions2.SpaceWithinMethodDeclarationParenthesis, fallbackOptions.Spacing.HasFlag(SpacePlacement.WithinMethodDeclarationParenthesis)) ? SpacePlacement.WithinMethodDeclarationParenthesis : 0) | - (options.GetEditorConfigOption(CSharpFormattingOptions2.SpaceAfterMethodCallName, fallbackOptions.Spacing.HasFlag(SpacePlacement.AfterMethodCallName)) ? SpacePlacement.AfterMethodCallName : 0) | - (options.GetEditorConfigOption(CSharpFormattingOptions2.SpaceBetweenEmptyMethodCallParentheses, fallbackOptions.Spacing.HasFlag(SpacePlacement.BetweenEmptyMethodCallParentheses)) ? SpacePlacement.BetweenEmptyMethodCallParentheses : 0) | - (options.GetEditorConfigOption(CSharpFormattingOptions2.SpaceWithinMethodCallParentheses, fallbackOptions.Spacing.HasFlag(SpacePlacement.WithinMethodCallParentheses)) ? SpacePlacement.WithinMethodCallParentheses : 0) | - (options.GetEditorConfigOption(CSharpFormattingOptions2.SpaceAfterControlFlowStatementKeyword, fallbackOptions.Spacing.HasFlag(SpacePlacement.AfterControlFlowStatementKeyword)) ? SpacePlacement.AfterControlFlowStatementKeyword : 0) | - options.GetEditorConfigOption(CSharpFormattingOptions2.SpaceBetweenParentheses, fallbackOptions.Spacing.ToSpacingWithinParentheses()).ToSpacePlacement() | - (options.GetEditorConfigOption(CSharpFormattingOptions2.SpaceBeforeSemicolonsInForStatement, fallbackOptions.Spacing.HasFlag(SpacePlacement.BeforeSemicolonsInForStatement)) ? SpacePlacement.BeforeSemicolonsInForStatement : 0) | - (options.GetEditorConfigOption(CSharpFormattingOptions2.SpaceAfterSemicolonsInForStatement, fallbackOptions.Spacing.HasFlag(SpacePlacement.AfterSemicolonsInForStatement)) ? SpacePlacement.AfterSemicolonsInForStatement : 0) | - (options.GetEditorConfigOption(CSharpFormattingOptions2.SpaceAfterCast, fallbackOptions.Spacing.HasFlag(SpacePlacement.AfterCast)) ? SpacePlacement.AfterCast : 0) | - (options.GetEditorConfigOption(CSharpFormattingOptions2.SpaceBeforeOpenSquareBracket, fallbackOptions.Spacing.HasFlag(SpacePlacement.BeforeOpenSquareBracket)) ? SpacePlacement.BeforeOpenSquareBracket : 0) | - (options.GetEditorConfigOption(CSharpFormattingOptions2.SpaceBetweenEmptySquareBrackets, fallbackOptions.Spacing.HasFlag(SpacePlacement.BetweenEmptySquareBrackets)) ? SpacePlacement.BetweenEmptySquareBrackets : 0) | - (options.GetEditorConfigOption(CSharpFormattingOptions2.SpaceWithinSquareBrackets, fallbackOptions.Spacing.HasFlag(SpacePlacement.WithinSquareBrackets)) ? SpacePlacement.WithinSquareBrackets : 0) | - (options.GetEditorConfigOption(CSharpFormattingOptions2.SpaceAfterColonInBaseTypeDeclaration, fallbackOptions.Spacing.HasFlag(SpacePlacement.AfterColonInBaseTypeDeclaration)) ? SpacePlacement.AfterColonInBaseTypeDeclaration : 0) | - (options.GetEditorConfigOption(CSharpFormattingOptions2.SpaceBeforeColonInBaseTypeDeclaration, fallbackOptions.Spacing.HasFlag(SpacePlacement.BeforeColonInBaseTypeDeclaration)) ? SpacePlacement.BeforeColonInBaseTypeDeclaration : 0) | - (options.GetEditorConfigOption(CSharpFormattingOptions2.SpaceAfterComma, fallbackOptions.Spacing.HasFlag(SpacePlacement.AfterComma)) ? SpacePlacement.AfterComma : 0) | - (options.GetEditorConfigOption(CSharpFormattingOptions2.SpaceBeforeComma, fallbackOptions.Spacing.HasFlag(SpacePlacement.BeforeComma)) ? SpacePlacement.BeforeComma : 0) | - (options.GetEditorConfigOption(CSharpFormattingOptions2.SpaceAfterDot, fallbackOptions.Spacing.HasFlag(SpacePlacement.AfterDot)) ? SpacePlacement.AfterDot : 0) | - (options.GetEditorConfigOption(CSharpFormattingOptions2.SpaceBeforeDot, fallbackOptions.Spacing.HasFlag(SpacePlacement.BeforeDot)) ? SpacePlacement.BeforeDot : 0), - SpacingAroundBinaryOperator = options.GetEditorConfigOption(CSharpFormattingOptions2.SpacingAroundBinaryOperator, fallbackOptions.SpacingAroundBinaryOperator), + (options.GetOption(CSharpFormattingOptions2.SpacesIgnoreAroundVariableDeclaration, fallbackOptions.Spacing.HasFlag(SpacePlacement.IgnoreAroundVariableDeclaration)) ? SpacePlacement.IgnoreAroundVariableDeclaration : 0) | + (options.GetOption(CSharpFormattingOptions2.SpacingAfterMethodDeclarationName, fallbackOptions.Spacing.HasFlag(SpacePlacement.AfterMethodDeclarationName)) ? SpacePlacement.AfterMethodDeclarationName : 0) | + (options.GetOption(CSharpFormattingOptions2.SpaceBetweenEmptyMethodDeclarationParentheses, fallbackOptions.Spacing.HasFlag(SpacePlacement.BetweenEmptyMethodDeclarationParentheses)) ? SpacePlacement.BetweenEmptyMethodDeclarationParentheses : 0) | + (options.GetOption(CSharpFormattingOptions2.SpaceWithinMethodDeclarationParenthesis, fallbackOptions.Spacing.HasFlag(SpacePlacement.WithinMethodDeclarationParenthesis)) ? SpacePlacement.WithinMethodDeclarationParenthesis : 0) | + (options.GetOption(CSharpFormattingOptions2.SpaceAfterMethodCallName, fallbackOptions.Spacing.HasFlag(SpacePlacement.AfterMethodCallName)) ? SpacePlacement.AfterMethodCallName : 0) | + (options.GetOption(CSharpFormattingOptions2.SpaceBetweenEmptyMethodCallParentheses, fallbackOptions.Spacing.HasFlag(SpacePlacement.BetweenEmptyMethodCallParentheses)) ? SpacePlacement.BetweenEmptyMethodCallParentheses : 0) | + (options.GetOption(CSharpFormattingOptions2.SpaceWithinMethodCallParentheses, fallbackOptions.Spacing.HasFlag(SpacePlacement.WithinMethodCallParentheses)) ? SpacePlacement.WithinMethodCallParentheses : 0) | + (options.GetOption(CSharpFormattingOptions2.SpaceAfterControlFlowStatementKeyword, fallbackOptions.Spacing.HasFlag(SpacePlacement.AfterControlFlowStatementKeyword)) ? SpacePlacement.AfterControlFlowStatementKeyword : 0) | + options.GetOption(CSharpFormattingOptions2.SpaceBetweenParentheses, fallbackOptions.Spacing.ToSpacingWithinParentheses()).ToSpacePlacement() | + (options.GetOption(CSharpFormattingOptions2.SpaceBeforeSemicolonsInForStatement, fallbackOptions.Spacing.HasFlag(SpacePlacement.BeforeSemicolonsInForStatement)) ? SpacePlacement.BeforeSemicolonsInForStatement : 0) | + (options.GetOption(CSharpFormattingOptions2.SpaceAfterSemicolonsInForStatement, fallbackOptions.Spacing.HasFlag(SpacePlacement.AfterSemicolonsInForStatement)) ? SpacePlacement.AfterSemicolonsInForStatement : 0) | + (options.GetOption(CSharpFormattingOptions2.SpaceAfterCast, fallbackOptions.Spacing.HasFlag(SpacePlacement.AfterCast)) ? SpacePlacement.AfterCast : 0) | + (options.GetOption(CSharpFormattingOptions2.SpaceBeforeOpenSquareBracket, fallbackOptions.Spacing.HasFlag(SpacePlacement.BeforeOpenSquareBracket)) ? SpacePlacement.BeforeOpenSquareBracket : 0) | + (options.GetOption(CSharpFormattingOptions2.SpaceBetweenEmptySquareBrackets, fallbackOptions.Spacing.HasFlag(SpacePlacement.BetweenEmptySquareBrackets)) ? SpacePlacement.BetweenEmptySquareBrackets : 0) | + (options.GetOption(CSharpFormattingOptions2.SpaceWithinSquareBrackets, fallbackOptions.Spacing.HasFlag(SpacePlacement.WithinSquareBrackets)) ? SpacePlacement.WithinSquareBrackets : 0) | + (options.GetOption(CSharpFormattingOptions2.SpaceAfterColonInBaseTypeDeclaration, fallbackOptions.Spacing.HasFlag(SpacePlacement.AfterColonInBaseTypeDeclaration)) ? SpacePlacement.AfterColonInBaseTypeDeclaration : 0) | + (options.GetOption(CSharpFormattingOptions2.SpaceBeforeColonInBaseTypeDeclaration, fallbackOptions.Spacing.HasFlag(SpacePlacement.BeforeColonInBaseTypeDeclaration)) ? SpacePlacement.BeforeColonInBaseTypeDeclaration : 0) | + (options.GetOption(CSharpFormattingOptions2.SpaceAfterComma, fallbackOptions.Spacing.HasFlag(SpacePlacement.AfterComma)) ? SpacePlacement.AfterComma : 0) | + (options.GetOption(CSharpFormattingOptions2.SpaceBeforeComma, fallbackOptions.Spacing.HasFlag(SpacePlacement.BeforeComma)) ? SpacePlacement.BeforeComma : 0) | + (options.GetOption(CSharpFormattingOptions2.SpaceAfterDot, fallbackOptions.Spacing.HasFlag(SpacePlacement.AfterDot)) ? SpacePlacement.AfterDot : 0) | + (options.GetOption(CSharpFormattingOptions2.SpaceBeforeDot, fallbackOptions.Spacing.HasFlag(SpacePlacement.BeforeDot)) ? SpacePlacement.BeforeDot : 0), + SpacingAroundBinaryOperator = options.GetOption(CSharpFormattingOptions2.SpacingAroundBinaryOperator, fallbackOptions.SpacingAroundBinaryOperator), NewLines = - (options.GetEditorConfigOption(CSharpFormattingOptions2.NewLineForMembersInObjectInit, fallbackOptions.NewLines.HasFlag(NewLinePlacement.BeforeMembersInObjectInitializers)) ? NewLinePlacement.BeforeMembersInObjectInitializers : 0) | - (options.GetEditorConfigOption(CSharpFormattingOptions2.NewLineForMembersInAnonymousTypes, fallbackOptions.NewLines.HasFlag(NewLinePlacement.BeforeMembersInAnonymousTypes)) ? NewLinePlacement.BeforeMembersInAnonymousTypes : 0) | - (options.GetEditorConfigOption(CSharpFormattingOptions2.NewLineForElse, fallbackOptions.NewLines.HasFlag(NewLinePlacement.BeforeElse)) ? NewLinePlacement.BeforeElse : 0) | - (options.GetEditorConfigOption(CSharpFormattingOptions2.NewLineForCatch, fallbackOptions.NewLines.HasFlag(NewLinePlacement.BeforeCatch)) ? NewLinePlacement.BeforeCatch : 0) | - (options.GetEditorConfigOption(CSharpFormattingOptions2.NewLineForFinally, fallbackOptions.NewLines.HasFlag(NewLinePlacement.BeforeFinally)) ? NewLinePlacement.BeforeFinally : 0) | - options.GetEditorConfigOption(CSharpFormattingOptions2.NewLineBeforeOpenBrace, fallbackOptions.NewLines.ToNewLineBeforeOpenBracePlacement()).ToNewLinePlacement() | - (options.GetEditorConfigOption(CSharpFormattingOptions2.NewLineForClausesInQuery, fallbackOptions.NewLines.HasFlag(NewLinePlacement.BetweenQueryExpressionClauses)) ? NewLinePlacement.BetweenQueryExpressionClauses : 0), - LabelPositioning = options.GetEditorConfigOption(CSharpFormattingOptions2.LabelPositioning, fallbackOptions.LabelPositioning), + (options.GetOption(CSharpFormattingOptions2.NewLineForMembersInObjectInit, fallbackOptions.NewLines.HasFlag(NewLinePlacement.BeforeMembersInObjectInitializers)) ? NewLinePlacement.BeforeMembersInObjectInitializers : 0) | + (options.GetOption(CSharpFormattingOptions2.NewLineForMembersInAnonymousTypes, fallbackOptions.NewLines.HasFlag(NewLinePlacement.BeforeMembersInAnonymousTypes)) ? NewLinePlacement.BeforeMembersInAnonymousTypes : 0) | + (options.GetOption(CSharpFormattingOptions2.NewLineForElse, fallbackOptions.NewLines.HasFlag(NewLinePlacement.BeforeElse)) ? NewLinePlacement.BeforeElse : 0) | + (options.GetOption(CSharpFormattingOptions2.NewLineForCatch, fallbackOptions.NewLines.HasFlag(NewLinePlacement.BeforeCatch)) ? NewLinePlacement.BeforeCatch : 0) | + (options.GetOption(CSharpFormattingOptions2.NewLineForFinally, fallbackOptions.NewLines.HasFlag(NewLinePlacement.BeforeFinally)) ? NewLinePlacement.BeforeFinally : 0) | + options.GetOption(CSharpFormattingOptions2.NewLineBeforeOpenBrace, fallbackOptions.NewLines.ToNewLineBeforeOpenBracePlacement()).ToNewLinePlacement() | + (options.GetOption(CSharpFormattingOptions2.NewLineForClausesInQuery, fallbackOptions.NewLines.HasFlag(NewLinePlacement.BetweenQueryExpressionClauses)) ? NewLinePlacement.BetweenQueryExpressionClauses : 0), + LabelPositioning = options.GetOption(CSharpFormattingOptions2.LabelPositioning, fallbackOptions.LabelPositioning), Indentation = - (options.GetEditorConfigOption(CSharpFormattingOptions2.IndentBraces, fallbackOptions.Indentation.HasFlag(IndentationPlacement.Braces)) ? IndentationPlacement.Braces : 0) | - (options.GetEditorConfigOption(CSharpFormattingOptions2.IndentBlock, fallbackOptions.Indentation.HasFlag(IndentationPlacement.BlockContents)) ? IndentationPlacement.BlockContents : 0) | - (options.GetEditorConfigOption(CSharpFormattingOptions2.IndentSwitchCaseSection, fallbackOptions.Indentation.HasFlag(IndentationPlacement.SwitchCaseContents)) ? IndentationPlacement.SwitchCaseContents : 0) | - (options.GetEditorConfigOption(CSharpFormattingOptions2.IndentSwitchCaseSectionWhenBlock, fallbackOptions.Indentation.HasFlag(IndentationPlacement.SwitchCaseContentsWhenBlock)) ? IndentationPlacement.SwitchCaseContentsWhenBlock : 0) | - (options.GetEditorConfigOption(CSharpFormattingOptions2.IndentSwitchSection, fallbackOptions.Indentation.HasFlag(IndentationPlacement.SwitchSection)) ? IndentationPlacement.SwitchSection : 0), - WrappingKeepStatementsOnSingleLine = options.GetEditorConfigOption(CSharpFormattingOptions2.WrappingKeepStatementsOnSingleLine, fallbackOptions.WrappingKeepStatementsOnSingleLine), - WrappingPreserveSingleLine = options.GetEditorConfigOption(CSharpFormattingOptions2.WrappingPreserveSingleLine, fallbackOptions.WrappingPreserveSingleLine), - NamespaceDeclarations = options.GetEditorConfigOption(CSharpCodeStyleOptions.NamespaceDeclarations, fallbackOptions.NamespaceDeclarations), - PreferTopLevelStatements = options.GetEditorConfigOption(CSharpCodeStyleOptions.PreferTopLevelStatements, fallbackOptions.PreferTopLevelStatements) + (options.GetOption(CSharpFormattingOptions2.IndentBraces, fallbackOptions.Indentation.HasFlag(IndentationPlacement.Braces)) ? IndentationPlacement.Braces : 0) | + (options.GetOption(CSharpFormattingOptions2.IndentBlock, fallbackOptions.Indentation.HasFlag(IndentationPlacement.BlockContents)) ? IndentationPlacement.BlockContents : 0) | + (options.GetOption(CSharpFormattingOptions2.IndentSwitchCaseSection, fallbackOptions.Indentation.HasFlag(IndentationPlacement.SwitchCaseContents)) ? IndentationPlacement.SwitchCaseContents : 0) | + (options.GetOption(CSharpFormattingOptions2.IndentSwitchCaseSectionWhenBlock, fallbackOptions.Indentation.HasFlag(IndentationPlacement.SwitchCaseContentsWhenBlock)) ? IndentationPlacement.SwitchCaseContentsWhenBlock : 0) | + (options.GetOption(CSharpFormattingOptions2.IndentSwitchSection, fallbackOptions.Indentation.HasFlag(IndentationPlacement.SwitchSection)) ? IndentationPlacement.SwitchSection : 0), + WrappingKeepStatementsOnSingleLine = options.GetOption(CSharpFormattingOptions2.WrappingKeepStatementsOnSingleLine, fallbackOptions.WrappingKeepStatementsOnSingleLine), + WrappingPreserveSingleLine = options.GetOption(CSharpFormattingOptions2.WrappingPreserveSingleLine, fallbackOptions.WrappingPreserveSingleLine), + NamespaceDeclarations = options.GetOption(CSharpCodeStyleOptions.NamespaceDeclarations, fallbackOptions.NamespaceDeclarations), + PreferTopLevelStatements = options.GetOption(CSharpCodeStyleOptions.PreferTopLevelStatements, fallbackOptions.PreferTopLevelStatements) }; } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/NewLineBeforeOpenBracePlacement.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/NewLineBeforeOpenBracePlacement.cs index 7198b0d4b637e..8aa89c7a3db1f 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/NewLineBeforeOpenBracePlacement.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/NewLineBeforeOpenBracePlacement.cs @@ -45,4 +45,7 @@ public static NewLinePlacement ToNewLinePlacement(this NewLineBeforeOpenBracePla (value.HasFlag(NewLineBeforeOpenBracePlacement.ObjectCollectionArrayInitializers) ? NewLinePlacement.BeforeOpenBraceInObjectCollectionArrayInitializers : 0) | (value.HasFlag(NewLineBeforeOpenBracePlacement.LambdaExpressionBody) ? NewLinePlacement.BeforeOpenBraceInLambdaExpressionBody : 0) | (value.HasFlag(NewLineBeforeOpenBracePlacement.Accessors) ? NewLinePlacement.BeforeOpenBraceInAccessors : 0); + + public static NewLineBeforeOpenBracePlacement WithFlagValue(this NewLineBeforeOpenBracePlacement flags, NewLineBeforeOpenBracePlacement flag, bool value) + => (flags & ~flag) | (value ? flag : 0); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/SpacingWithinParentheses.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/SpacingWithinParentheses.cs index cfcd1eeabe261..74fe69b8916d0 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/SpacingWithinParentheses.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/SpacingWithinParentheses.cs @@ -26,5 +26,7 @@ public static SpacePlacement ToSpacePlacement(this SpacePlacementWithinParenthes => (placement.HasFlag(SpacePlacementWithinParentheses.Expressions) ? SpacePlacement.WithinExpressionParentheses : 0) | (placement.HasFlag(SpacePlacementWithinParentheses.TypeCasts) ? SpacePlacement.WithinCastParentheses : 0) | (placement.HasFlag(SpacePlacementWithinParentheses.ControlFlowStatements) ? SpacePlacement.WithinOtherParentheses : 0); -} + public static SpacePlacementWithinParentheses WithFlagValue(this SpacePlacementWithinParentheses flags, SpacePlacementWithinParentheses flag, bool value) + => (flags & ~flag) | (value ? flag : 0); +} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/CSharpSimplification.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/CSharpSimplification.cs index 992685b730a86..dbbc34ff10105 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/CSharpSimplification.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/CSharpSimplification.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Simplification; namespace Microsoft.CodeAnalysis.CSharp.Simplification; @@ -14,6 +14,6 @@ internal sealed class CSharpSimplification : AbstractSimplification public override SimplifierOptions DefaultOptions => CSharpSimplifierOptions.Default; - public override SimplifierOptions GetSimplifierOptions(AnalyzerConfigOptions options, SimplifierOptions? fallbackOptions) + public override SimplifierOptions GetSimplifierOptions(IOptionsReader options, SimplifierOptions? fallbackOptions) => options.GetCSharpSimplifierOptions((CSharpSimplifierOptions?)fallbackOptions); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/CSharpSimplifierOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/CSharpSimplifierOptions.cs index 5d726afe1e390..875660b143b89 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/CSharpSimplifierOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/CSharpSimplifierOptions.cs @@ -9,6 +9,7 @@ using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Simplification; using Roslyn.Utilities; @@ -65,20 +66,20 @@ public override int GetHashCode() internal static class CSharpSimplifierOptionsProviders { - public static CSharpSimplifierOptions GetCSharpSimplifierOptions(this AnalyzerConfigOptions options, CSharpSimplifierOptions? fallbackOptions) + public static CSharpSimplifierOptions GetCSharpSimplifierOptions(this IOptionsReader options, CSharpSimplifierOptions? fallbackOptions) { fallbackOptions ??= CSharpSimplifierOptions.Default; return new() { - Common = options.GetCommonSimplifierOptions(fallbackOptions.Common), - VarForBuiltInTypes = options.GetEditorConfigOption(CSharpCodeStyleOptions.VarForBuiltInTypes, fallbackOptions.VarForBuiltInTypes), - VarWhenTypeIsApparent = options.GetEditorConfigOption(CSharpCodeStyleOptions.VarWhenTypeIsApparent, fallbackOptions.VarWhenTypeIsApparent), - VarElsewhere = options.GetEditorConfigOption(CSharpCodeStyleOptions.VarElsewhere, fallbackOptions.VarElsewhere), - PreferSimpleDefaultExpression = options.GetEditorConfigOption(CSharpCodeStyleOptions.PreferSimpleDefaultExpression, fallbackOptions.PreferSimpleDefaultExpression), - AllowEmbeddedStatementsOnSameLine = options.GetEditorConfigOption(CSharpCodeStyleOptions.AllowEmbeddedStatementsOnSameLine, fallbackOptions.AllowEmbeddedStatementsOnSameLine), - PreferBraces = options.GetEditorConfigOption(CSharpCodeStyleOptions.PreferBraces, fallbackOptions.PreferBraces), - PreferThrowExpression = options.GetEditorConfigOption(CSharpCodeStyleOptions.PreferThrowExpression, fallbackOptions.PreferThrowExpression) + Common = options.GetCommonSimplifierOptions(LanguageNames.CSharp, fallbackOptions.Common), + VarForBuiltInTypes = options.GetOption(CSharpCodeStyleOptions.VarForBuiltInTypes, fallbackOptions.VarForBuiltInTypes), + VarWhenTypeIsApparent = options.GetOption(CSharpCodeStyleOptions.VarWhenTypeIsApparent, fallbackOptions.VarWhenTypeIsApparent), + VarElsewhere = options.GetOption(CSharpCodeStyleOptions.VarElsewhere, fallbackOptions.VarElsewhere), + PreferSimpleDefaultExpression = options.GetOption(CSharpCodeStyleOptions.PreferSimpleDefaultExpression, fallbackOptions.PreferSimpleDefaultExpression), + AllowEmbeddedStatementsOnSameLine = options.GetOption(CSharpCodeStyleOptions.AllowEmbeddedStatementsOnSameLine, fallbackOptions.AllowEmbeddedStatementsOnSameLine), + PreferBraces = options.GetOption(CSharpCodeStyleOptions.PreferBraces, fallbackOptions.PreferBraces), + PreferThrowExpression = options.GetOption(CSharpCodeStyleOptions.PreferThrowExpression, fallbackOptions.PreferThrowExpression) }; } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/AddImport/AddImportPlacementOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/AddImport/AddImportPlacementOptions.cs index 67a42f9889b5a..b648c5693b4a0 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/AddImport/AddImportPlacementOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/AddImport/AddImportPlacementOptions.cs @@ -7,8 +7,12 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Options; + +#if !CODE_STYLE +using Microsoft.CodeAnalysis.Host; +#endif namespace Microsoft.CodeAnalysis.AddImport; @@ -45,7 +49,7 @@ internal interface AddImportPlacementOptionsProvider internal static partial class AddImportPlacementOptionsProviders { #if !CODE_STYLE - public static AddImportPlacementOptions GetAddImportPlacementOptions(this AnalyzerConfigOptions options, bool allowInHiddenRegions, AddImportPlacementOptions? fallbackOptions, LanguageServices languageServices) + public static AddImportPlacementOptions GetAddImportPlacementOptions(this IOptionsReader options, bool allowInHiddenRegions, AddImportPlacementOptions? fallbackOptions, LanguageServices languageServices) => languageServices.GetRequiredService().GetAddImportOptions(options, allowInHiddenRegions, fallbackOptions); public static async ValueTask GetAddImportPlacementOptionsAsync(this Document document, AddImportPlacementOptions? fallbackOptions, CancellationToken cancellationToken) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeCleanup/CodeCleanupOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeCleanup/CodeCleanupOptions.cs index 09e5d2d6ff056..be934ffb09665 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeCleanup/CodeCleanupOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeCleanup/CodeCleanupOptions.cs @@ -8,12 +8,13 @@ using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.AddImport; -using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.CodeActions; using Roslyn.Utilities; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Options; #if !CODE_STYLE +using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.OrganizeImports; #endif @@ -84,7 +85,7 @@ async ValueTask OptionsProvider new() { FormattingOptions = options.GetSyntaxFormattingOptions(fallbackOptions?.FormattingOptions, languageServices), diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeGeneration/CleanCodeGenerationOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeGeneration/CleanCodeGenerationOptions.cs index 9cc7fb1756363..e0cfee0b46d40 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeGeneration/CleanCodeGenerationOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeGeneration/CleanCodeGenerationOptions.cs @@ -7,7 +7,10 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; + +#if !CODE_STYLE using Microsoft.CodeAnalysis.Host; +#endif namespace Microsoft.CodeAnalysis.CodeGeneration; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeGeneration/CodeGenerationOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeGeneration/CodeGenerationOptions.cs index fad46022618e4..7b0e57733de29 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeGeneration/CodeGenerationOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeGeneration/CodeGenerationOptions.cs @@ -2,20 +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.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.AddImport; using Roslyn.Utilities; using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Options; + +#if !CODE_STYLE +using Microsoft.CodeAnalysis.Host; +#endif namespace Microsoft.CodeAnalysis.CodeGeneration; @@ -112,24 +111,24 @@ internal interface CodeAndImportGenerationOptionsProvider : internal static class CodeGenerationOptionsProviders { - public static CodeGenerationOptions.CommonOptions GetCommonCodeGenerationOptions(this AnalyzerConfigOptions options, CodeGenerationOptions.CommonOptions? fallbackOptions) + public static CodeGenerationOptions.CommonOptions GetCommonCodeGenerationOptions(this IOptionsReader options, string language, CodeGenerationOptions.CommonOptions? fallbackOptions) { fallbackOptions ??= CodeGenerationOptions.CommonOptions.Default; return new() { - NamingStyle = options.GetEditorConfigOption(NamingStyleOptions.NamingPreferences, fallbackOptions.NamingStyle) + NamingStyle = options.GetOption(NamingStyleOptions.NamingPreferences, language, fallbackOptions.NamingStyle) }; } #if !CODE_STYLE - public static CodeGenerationOptions GetCodeGenerationOptions(this AnalyzerConfigOptions options, CodeGenerationOptions? fallbackOptions, LanguageServices languageServices) + public static CodeGenerationOptions GetCodeGenerationOptions(this IOptionsReader options, LanguageServices languageServices, CodeGenerationOptions? fallbackOptions) => languageServices.GetRequiredService().GetCodeGenerationOptions(options, fallbackOptions); public static async ValueTask GetCodeGenerationOptionsAsync(this Document document, CodeGenerationOptions? fallbackOptions, CancellationToken cancellationToken) { var configOptions = await document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); - return configOptions.GetCodeGenerationOptions(fallbackOptions, document.Project.Services); + return configOptions.GetCodeGenerationOptions(document.Project.Services, fallbackOptions); } public static async ValueTask GetCodeGenerationOptionsAsync(this Document document, CodeGenerationOptionsProvider fallbackOptionsProvider, CancellationToken cancellationToken) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/CodeStyleHelpers.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/CodeStyleHelpers.cs index f0caa8d7fd329..431a3b863be17 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/CodeStyleHelpers.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/CodeStyleHelpers.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Collections.Immutable; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; @@ -112,31 +113,39 @@ private static bool TryParseNotification(string value, out NotificationOption2 n return false; } - public static Option2 CreateOption( + public static Option2> CreateEditorConfigOption( + this ImmutableArray.Builder optionsBuilder, + string name, + CodeStyleOption2 defaultValue, OptionGroup group, - string feature, + string? languageName = null, + Func, EditorConfigValueSerializer>>? serializerFactory = null) + { + var option = new Option2>(name, defaultValue, group, languageName, isEditorConfigOption: true, serializer: (serializerFactory ?? EditorConfigValueSerializer.CodeStyle).Invoke(defaultValue)); + optionsBuilder.Add(option); + return option; + } + + public static Option2 CreateEditorConfigOption( + this ImmutableArray.Builder optionsBuilder, string name, T defaultValue, - ImmutableArray.Builder optionsBuilder, - OptionStorageLocation2 storageLocation, - string languageName) + OptionGroup group, + EditorConfigValueSerializer? serializer = null) { - var option = new Option2(feature, group, name, defaultValue, ImmutableArray.Create(storageLocation), languageName); + var option = new Option2(name, defaultValue, group, languageName: null, isEditorConfigOption: true, serializer: serializer); optionsBuilder.Add(option); return option; } - public static Option2 CreateOption( - OptionGroup group, - string feature, + public static PerLanguageOption2> CreatePerLanguageEditorConfigOption( + this ImmutableArray.Builder optionsBuilder, string name, - T defaultValue, - ImmutableArray.Builder optionsBuilder, - OptionStorageLocation2 storageLocation1, - OptionStorageLocation2 storageLocation2, - string languageName) + CodeStyleOption2 defaultValue, + OptionGroup group, + Func, EditorConfigValueSerializer>>? serializerFactory = null) { - var option = new Option2(feature, group, name, defaultValue, ImmutableArray.Create(storageLocation1, storageLocation2), languageName); + var option = new PerLanguageOption2>(name, defaultValue, group, isEditorConfigOption: true, serializer: (serializerFactory ?? EditorConfigValueSerializer.CodeStyle).Invoke(defaultValue)); optionsBuilder.Add(option); return option; } @@ -151,26 +160,9 @@ public static Option2 CreateOption( KeyValuePairUtil.Create("unused_local_variable", UnusedValuePreference.UnusedLocalVariable), }); - public static Option2> CreateUnusedExpressionAssignmentOption( - OptionGroup group, - string feature, - string name, - string editorConfigName, - CodeStyleOption2 defaultValue, - ImmutableArray.Builder optionsBuilder, - string languageName) - => CreateOption( - group, - feature, - name, - defaultValue, - optionsBuilder, - new EditorConfigStorageLocation>( - editorConfigName, - s => ParseUnusedExpressionAssignmentPreference(s, defaultValue), - o => GetUnusedExpressionAssignmentPreferenceEditorConfigString(o, defaultValue)), - new RoamingProfileStorageLocation($"TextEditor.%LANGUAGE%.Specific.{name}Preference"), - languageName); + internal static EditorConfigValueSerializer> GetUnusedValuePreferenceSerializer(CodeStyleOption2 defaultValue) + => new(parseValue: str => ParseUnusedExpressionAssignmentPreference(str, defaultValue), + serializeValue: value => GetUnusedExpressionAssignmentPreferenceEditorConfigString(value, defaultValue)); private static Optional> ParseUnusedExpressionAssignmentPreference( string optionString, diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/CodeStyleOption2`1.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/CodeStyleOption2`1.cs index c23e79bbb0aee..dc117c7ae422c 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/CodeStyleOption2`1.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/CodeStyleOption2`1.cs @@ -20,10 +20,15 @@ internal interface ICodeStyleOption ICodeStyleOption WithNotification(NotificationOption2 notification); ICodeStyleOption AsCodeStyleOption(); #if !CODE_STYLE + ICodeStyleOption AsInternalCodeStyleOption(); ICodeStyleOption AsPublicCodeStyleOption(); #endif } + internal interface ICodeStyleOption2 : ICodeStyleOption + { + } + /// /// Represents a code style option and an associated notification option. Supports /// being instantiated with T as a or an enum type. @@ -39,7 +44,7 @@ internal interface ICodeStyleOption /// then those values will write back as false/true. /// [DataContract] - internal sealed partial class CodeStyleOption2 : ICodeStyleOption, IEquatable?> + internal sealed partial class CodeStyleOption2 : ICodeStyleOption2, IEquatable?> { public static readonly CodeStyleOption2 Default = new(default!, NotificationOption2.Silent); @@ -74,6 +79,7 @@ public CodeStyleOption2(T value, NotificationOption2 notification) ICodeStyleOption ICodeStyleOption.AsCodeStyleOption() => this is TCodeStyleOption ? this : new CodeStyleOption(this); ICodeStyleOption ICodeStyleOption.AsPublicCodeStyleOption() => new CodeStyleOption(this); + ICodeStyleOption ICodeStyleOption.AsInternalCodeStyleOption() => this; #endif #pragma warning restore diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/CodeStyleOptions2.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/CodeStyleOptions2.cs index 0244ad6783a2d..317e5e62aeae2 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/CodeStyleOptions2.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/CodeStyleOptions2.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Collections.Immutable; using System.Diagnostics; using Microsoft.CodeAnalysis.Diagnostics; @@ -9,65 +10,26 @@ using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Simplification; using Roslyn.Utilities; -using static Microsoft.CodeAnalysis.CodeStyle.CodeStyleHelpers; namespace Microsoft.CodeAnalysis.CodeStyle { internal static class CodeStyleOptions2 { + private const string PublicFeatureName = "CodeStyleOptions"; + private static readonly ImmutableArray.Builder s_allOptionsBuilder = ImmutableArray.CreateBuilder(); - internal static ImmutableArray AllOptions { get; } - - private static PerLanguageOption2 CreateOption( - OptionGroup group, string name, T defaultValue, - OptionStorageLocation2 storageLocation) - { - var option = new PerLanguageOption2( - "CodeStyleOptions", - group, name, defaultValue, - ImmutableArray.Create(storageLocation)); - - s_allOptionsBuilder.Add(option); - return option; - } - - private static PerLanguageOption2 CreateOption( - OptionGroup group, string name, T defaultValue, - OptionStorageLocation2 storageLocation1, OptionStorageLocation2 storageLocation2) - { - var option = new PerLanguageOption2( - "CodeStyleOptions", - group, name, defaultValue, - ImmutableArray.Create(storageLocation1, storageLocation2)); - - s_allOptionsBuilder.Add(option); - return option; - } - - private static Option2 CreateCommonOption(OptionGroup group, string name, T defaultValue, OptionStorageLocation2 storageLocation) - { - var option = new Option2( - "CodeStyleOptions", - group, name, defaultValue, - ImmutableArray.Create(storageLocation)); - - s_allOptionsBuilder.Add(option); - return option; - } - - private static Option2 CreateCommonOption( - OptionGroup group, string name, T defaultValue, - OptionStorageLocation2 storageLocation1, OptionStorageLocation2 storageLocation2) - { - var option = new Option2( - "CodeStyleOptions", - group, name, defaultValue, - ImmutableArray.Create(storageLocation1, storageLocation2)); - - s_allOptionsBuilder.Add(option); - return option; - } + private static PerLanguageOption2> CreatePerLanguageOption( + OptionGroup group, string name, CodeStyleOption2 defaultValue, Func, EditorConfigValueSerializer>>? serializerFactory = null) + => s_allOptionsBuilder.CreatePerLanguageEditorConfigOption(name, defaultValue, group, serializerFactory); + + private static Option2> CreateOption( + OptionGroup group, string name, CodeStyleOption2 defaultValue, Func, EditorConfigValueSerializer>>? serializerFactory = null) + => s_allOptionsBuilder.CreateEditorConfigOption(name, defaultValue, group, languageName: null, serializerFactory); + + private static Option2 CreateOption( + OptionGroup group, string name, T defaultValue, EditorConfigValueSerializer? serializer = null) + => s_allOptionsBuilder.CreateEditorConfigOption(name, defaultValue, group, serializer); /// /// When user preferences are not yet set for a style, we fall back to the default value. @@ -79,196 +41,160 @@ private static Option2 CreateCommonOption( internal static readonly CodeStyleOption2 TrueWithSuggestionEnforcement = new(value: true, notification: NotificationOption2.Suggestion); internal static readonly CodeStyleOption2 FalseWithSuggestionEnforcement = new(value: false, notification: NotificationOption2.Suggestion); - private static PerLanguageOption2> CreateOption( - OptionGroup group, string name, CodeStyleOption2 defaultValue, - string editorconfigKeyName, string roamingProfileStorageKeyName) - => CreateOption( - group, name, defaultValue, - EditorConfigStorageLocation.ForBoolCodeStyleOption(editorconfigKeyName, defaultValue), - new RoamingProfileStorageLocation(roamingProfileStorageKeyName)); - - private static PerLanguageOption2> CreateQualifyAccessOption(string optionName, string editorconfigKeyName) - => CreateOption( - CodeStyleOptionGroups.ThisOrMe, - optionName, - defaultValue: SimplifierOptions.DefaultQualifyAccess, - editorconfigKeyName, - $"TextEditor.%LANGUAGE%.Specific.{optionName}"); + private static PerLanguageOption2> CreateQualifyAccessOption(string name) + => CreatePerLanguageOption(CodeStyleOptionGroups.ThisOrMe, name, defaultValue: SimplifierOptions.DefaultQualifyAccess); /// /// This option says if we should simplify away the . or . in field access expressions. /// public static readonly PerLanguageOption2> QualifyFieldAccess = CreateQualifyAccessOption( - nameof(QualifyFieldAccess), "dotnet_style_qualification_for_field"); + "dotnet_style_qualification_for_field") + .WithPublicOption(PublicFeatureName, "QualifyFieldAccess"); /// /// This option says if we should simplify away the . or . in property access expressions. /// public static readonly PerLanguageOption2> QualifyPropertyAccess = CreateQualifyAccessOption( - nameof(QualifyPropertyAccess), "dotnet_style_qualification_for_property"); + "dotnet_style_qualification_for_property") + .WithPublicOption(PublicFeatureName, "QualifyPropertyAccess"); /// /// This option says if we should simplify away the . or . in method access expressions. /// public static readonly PerLanguageOption2> QualifyMethodAccess = CreateQualifyAccessOption( - nameof(QualifyMethodAccess), "dotnet_style_qualification_for_method"); + "dotnet_style_qualification_for_method") + .WithPublicOption(PublicFeatureName, "QualifyMethodAccess"); /// /// This option says if we should simplify away the . or . in event access expressions. /// public static readonly PerLanguageOption2> QualifyEventAccess = CreateQualifyAccessOption( - nameof(QualifyEventAccess), "dotnet_style_qualification_for_event"); + "dotnet_style_qualification_for_event") + .WithPublicOption(PublicFeatureName, "QualifyEventAccess"); /// /// This option says if we should prefer keyword for Intrinsic Predefined Types in Declarations /// - public static readonly PerLanguageOption2> PreferIntrinsicPredefinedTypeKeywordInDeclaration = CreateOption( - CodeStyleOptionGroups.PredefinedTypeNameUsage, nameof(PreferIntrinsicPredefinedTypeKeywordInDeclaration), + public static readonly PerLanguageOption2> PreferIntrinsicPredefinedTypeKeywordInDeclaration = CreatePerLanguageOption( + CodeStyleOptionGroups.PredefinedTypeNameUsage, defaultValue: SimplifierOptions.DefaultPreferPredefinedTypeKeyword, - "dotnet_style_predefined_type_for_locals_parameters_members", - "TextEditor.%LANGUAGE%.Specific.PreferIntrinsicPredefinedTypeKeywordInDeclaration.CodeStyle"); + name: "dotnet_style_predefined_type_for_locals_parameters_members") + .WithPublicOption(PublicFeatureName, "PreferIntrinsicPredefinedTypeKeywordInDeclaration"); /// /// This option says if we should prefer keyword for Intrinsic Predefined Types in Member Access Expression /// - public static readonly PerLanguageOption2> PreferIntrinsicPredefinedTypeKeywordInMemberAccess = CreateOption( - CodeStyleOptionGroups.PredefinedTypeNameUsage, nameof(PreferIntrinsicPredefinedTypeKeywordInMemberAccess), + public static readonly PerLanguageOption2> PreferIntrinsicPredefinedTypeKeywordInMemberAccess = CreatePerLanguageOption( + CodeStyleOptionGroups.PredefinedTypeNameUsage, defaultValue: SimplifierOptions.DefaultPreferPredefinedTypeKeyword, - "dotnet_style_predefined_type_for_member_access", - "TextEditor.%LANGUAGE%.Specific.PreferIntrinsicPredefinedTypeKeywordInMemberAccess.CodeStyle"); + name: "dotnet_style_predefined_type_for_member_access") + .WithPublicOption(PublicFeatureName, "PreferIntrinsicPredefinedTypeKeywordInMemberAccess"); - internal static readonly PerLanguageOption2> PreferObjectInitializer = CreateOption( - CodeStyleOptionGroups.ExpressionLevelPreferences, nameof(PreferObjectInitializer), - IdeCodeStyleOptions.CommonOptions.Default.PreferObjectInitializer, + internal static readonly PerLanguageOption2> PreferObjectInitializer = CreatePerLanguageOption( + CodeStyleOptionGroups.ExpressionLevelPreferences, "dotnet_style_object_initializer", - "TextEditor.%LANGUAGE%.Specific.PreferObjectInitializer"); + IdeCodeStyleOptions.CommonOptions.Default.PreferObjectInitializer); - internal static readonly PerLanguageOption2> PreferCollectionInitializer = CreateOption( - CodeStyleOptionGroups.ExpressionLevelPreferences, nameof(PreferCollectionInitializer), - IdeCodeStyleOptions.CommonOptions.Default.PreferCollectionInitializer, + internal static readonly PerLanguageOption2> PreferCollectionInitializer = CreatePerLanguageOption( + CodeStyleOptionGroups.ExpressionLevelPreferences, "dotnet_style_collection_initializer", - "TextEditor.%LANGUAGE%.Specific.PreferCollectionInitializer"); + IdeCodeStyleOptions.CommonOptions.Default.PreferCollectionInitializer); - internal static readonly PerLanguageOption2> PreferSimplifiedBooleanExpressions = CreateOption( - CodeStyleOptionGroups.ExpressionLevelPreferences, nameof(PreferSimplifiedBooleanExpressions), - IdeCodeStyleOptions.CommonOptions.Default.PreferSimplifiedBooleanExpressions, + internal static readonly PerLanguageOption2> PreferSimplifiedBooleanExpressions = CreatePerLanguageOption( + CodeStyleOptionGroups.ExpressionLevelPreferences, "dotnet_style_prefer_simplified_boolean_expressions", - "TextEditor.%LANGUAGE%.Specific.PreferSimplifiedBooleanExpressions"); - - internal static readonly Option2 OperatorPlacementWhenWrapping = - CreateCommonOption( - CodeStyleOptionGroups.ExpressionLevelPreferences, - nameof(OperatorPlacementWhenWrapping), - IdeCodeStyleOptions.CommonOptions.Default.OperatorPlacementWhenWrapping, - new EditorConfigStorageLocation( - "dotnet_style_operator_placement_when_wrapping", - OperatorPlacementUtilities.Parse, - OperatorPlacementUtilities.GetEditorConfigString)); - - internal static readonly PerLanguageOption2> PreferCoalesceExpression = CreateOption( - CodeStyleOptionGroups.ExpressionLevelPreferences, nameof(PreferCoalesceExpression), - IdeCodeStyleOptions.CommonOptions.Default.PreferCoalesceExpression, + IdeCodeStyleOptions.CommonOptions.Default.PreferSimplifiedBooleanExpressions); + + internal static readonly Option2 OperatorPlacementWhenWrapping = CreateOption( + CodeStyleOptionGroups.ExpressionLevelPreferences, + "dotnet_style_operator_placement_when_wrapping", + IdeCodeStyleOptions.CommonOptions.Default.OperatorPlacementWhenWrapping, + serializer: new( + parseValue: str => OperatorPlacementUtilities.Parse(str, IdeCodeStyleOptions.CommonOptions.Default.OperatorPlacementWhenWrapping), + serializeValue: OperatorPlacementUtilities.GetEditorConfigString)); + + internal static readonly PerLanguageOption2> PreferCoalesceExpression = CreatePerLanguageOption( + CodeStyleOptionGroups.ExpressionLevelPreferences, "dotnet_style_coalesce_expression", - "TextEditor.%LANGUAGE%.Specific.PreferCoalesceExpression"); + IdeCodeStyleOptions.CommonOptions.Default.PreferCoalesceExpression); - internal static readonly PerLanguageOption2> PreferNullPropagation = CreateOption( - CodeStyleOptionGroups.ExpressionLevelPreferences, nameof(PreferNullPropagation), - IdeCodeStyleOptions.CommonOptions.Default.PreferNullPropagation, + internal static readonly PerLanguageOption2> PreferNullPropagation = CreatePerLanguageOption( + CodeStyleOptionGroups.ExpressionLevelPreferences, "dotnet_style_null_propagation", - "TextEditor.%LANGUAGE%.Specific.PreferNullPropagation"); + IdeCodeStyleOptions.CommonOptions.Default.PreferNullPropagation); - internal static readonly PerLanguageOption2> PreferExplicitTupleNames = CreateOption( - CodeStyleOptionGroups.ExpressionLevelPreferences, nameof(PreferExplicitTupleNames), - IdeCodeStyleOptions.CommonOptions.Default.PreferExplicitTupleNames, + internal static readonly PerLanguageOption2> PreferExplicitTupleNames = CreatePerLanguageOption( + CodeStyleOptionGroups.ExpressionLevelPreferences, "dotnet_style_explicit_tuple_names", - "TextEditor.%LANGUAGE%.Specific.PreferExplicitTupleNames"); + IdeCodeStyleOptions.CommonOptions.Default.PreferExplicitTupleNames); - internal static readonly PerLanguageOption2> PreferAutoProperties = CreateOption( - CodeStyleOptionGroups.ExpressionLevelPreferences, nameof(PreferAutoProperties), - IdeCodeStyleOptions.CommonOptions.Default.PreferAutoProperties, + internal static readonly PerLanguageOption2> PreferAutoProperties = CreatePerLanguageOption( + CodeStyleOptionGroups.ExpressionLevelPreferences, "dotnet_style_prefer_auto_properties", - "TextEditor.%LANGUAGE%.Specific.PreferAutoProperties"); + IdeCodeStyleOptions.CommonOptions.Default.PreferAutoProperties); - internal static readonly PerLanguageOption2> PreferInferredTupleNames = CreateOption( - CodeStyleOptionGroups.ExpressionLevelPreferences, nameof(PreferInferredTupleNames), - IdeCodeStyleOptions.CommonOptions.Default.PreferInferredTupleNames, + internal static readonly PerLanguageOption2> PreferInferredTupleNames = CreatePerLanguageOption( + CodeStyleOptionGroups.ExpressionLevelPreferences, "dotnet_style_prefer_inferred_tuple_names", - $"TextEditor.%LANGUAGE%.Specific.{nameof(PreferInferredTupleNames)}"); + IdeCodeStyleOptions.CommonOptions.Default.PreferInferredTupleNames); - internal static readonly PerLanguageOption2> PreferInferredAnonymousTypeMemberNames = CreateOption( - CodeStyleOptionGroups.ExpressionLevelPreferences, nameof(PreferInferredAnonymousTypeMemberNames), - IdeCodeStyleOptions.CommonOptions.Default.PreferInferredAnonymousTypeMemberNames, + internal static readonly PerLanguageOption2> PreferInferredAnonymousTypeMemberNames = CreatePerLanguageOption( + CodeStyleOptionGroups.ExpressionLevelPreferences, "dotnet_style_prefer_inferred_anonymous_type_member_names", - $"TextEditor.%LANGUAGE%.Specific.PreferInferredAnonymousTypeMemberNames"); + IdeCodeStyleOptions.CommonOptions.Default.PreferInferredAnonymousTypeMemberNames); - internal static readonly PerLanguageOption2> PreferIsNullCheckOverReferenceEqualityMethod = CreateOption( - CodeStyleOptionGroups.ExpressionLevelPreferences, nameof(PreferIsNullCheckOverReferenceEqualityMethod), - IdeCodeStyleOptions.CommonOptions.Default.PreferIsNullCheckOverReferenceEqualityMethod, + internal static readonly PerLanguageOption2> PreferIsNullCheckOverReferenceEqualityMethod = CreatePerLanguageOption( + CodeStyleOptionGroups.ExpressionLevelPreferences, "dotnet_style_prefer_is_null_check_over_reference_equality_method", - $"TextEditor.%LANGUAGE%.Specific.PreferIsNullCheckOverReferenceEqualityMethod"); + IdeCodeStyleOptions.CommonOptions.Default.PreferIsNullCheckOverReferenceEqualityMethod); - internal static readonly PerLanguageOption2> PreferConditionalExpressionOverAssignment = CreateOption( - CodeStyleOptionGroups.ExpressionLevelPreferences, nameof(PreferConditionalExpressionOverAssignment), - IdeCodeStyleOptions.CommonOptions.Default.PreferConditionalExpressionOverAssignment, + internal static readonly PerLanguageOption2> PreferConditionalExpressionOverAssignment = CreatePerLanguageOption( + CodeStyleOptionGroups.ExpressionLevelPreferences, "dotnet_style_prefer_conditional_expression_over_assignment", - "TextEditor.%LANGUAGE%.Specific.PreferConditionalExpressionOverAssignment"); + IdeCodeStyleOptions.CommonOptions.Default.PreferConditionalExpressionOverAssignment); - internal static readonly PerLanguageOption2> PreferConditionalExpressionOverReturn = CreateOption( - CodeStyleOptionGroups.ExpressionLevelPreferences, nameof(PreferConditionalExpressionOverReturn), - IdeCodeStyleOptions.CommonOptions.Default.PreferConditionalExpressionOverReturn, + internal static readonly PerLanguageOption2> PreferConditionalExpressionOverReturn = CreatePerLanguageOption( + CodeStyleOptionGroups.ExpressionLevelPreferences, "dotnet_style_prefer_conditional_expression_over_return", - "TextEditor.%LANGUAGE%.Specific.PreferConditionalExpressionOverReturn"); + IdeCodeStyleOptions.CommonOptions.Default.PreferConditionalExpressionOverReturn); - internal static readonly PerLanguageOption2> PreferCompoundAssignment = CreateOption( + internal static readonly PerLanguageOption2> PreferCompoundAssignment = CreatePerLanguageOption( CodeStyleOptionGroups.ExpressionLevelPreferences, - nameof(PreferCompoundAssignment), - IdeCodeStyleOptions.CommonOptions.Default.PreferCompoundAssignment, "dotnet_style_prefer_compound_assignment", - "TextEditor.%LANGUAGE%.Specific.PreferCompoundAssignment"); + IdeCodeStyleOptions.CommonOptions.Default.PreferCompoundAssignment); - internal static readonly PerLanguageOption2> PreferSimplifiedInterpolation = CreateOption( - CodeStyleOptionGroups.ExpressionLevelPreferences, nameof(PreferSimplifiedInterpolation), - IdeCodeStyleOptions.CommonOptions.Default.PreferSimplifiedInterpolation, + internal static readonly PerLanguageOption2> PreferSimplifiedInterpolation = CreatePerLanguageOption( + CodeStyleOptionGroups.ExpressionLevelPreferences, "dotnet_style_prefer_simplified_interpolation", - $"TextEditor.%LANGUAGE%.Specific.PreferSimplifiedInterpolation"); + IdeCodeStyleOptions.CommonOptions.Default.PreferSimplifiedInterpolation); + + private static readonly BidirectionalMap s_unusedParametersPreferenceMap = + new(new[] + { + KeyValuePairUtil.Create("non_public", UnusedParametersPreference.NonPublicMethods), + KeyValuePairUtil.Create("all", UnusedParametersPreference.AllMethods), + }); - internal static readonly PerLanguageOption2> UnusedParameters = CreateOption( + internal static readonly PerLanguageOption2> UnusedParameters = CreatePerLanguageOption( CodeStyleOptionGroups.Parameter, - nameof(UnusedParameters), + "dotnet_code_quality_unused_parameters", IdeCodeStyleOptions.CommonOptions.Default.UnusedParameters, - new EditorConfigStorageLocation>( - "dotnet_code_quality_unused_parameters", - s => ParseUnusedParametersPreference(s, IdeCodeStyleOptions.CommonOptions.Default.UnusedParameters), - o => GetUnusedParametersPreferenceEditorConfigString(o, IdeCodeStyleOptions.CommonOptions.Default.UnusedParameters)), - new RoamingProfileStorageLocation($"TextEditor.%LANGUAGE%.Specific.UnusedParametersPreference")); - - internal static readonly PerLanguageOption2> AccessibilityModifiersRequired = - CreateOption( - CodeStyleOptionGroups.Modifier, "RequireAccessibilityModifiers", - IdeCodeStyleOptions.CommonOptions.Default.AccessibilityModifiersRequired, - new EditorConfigStorageLocation>( - "dotnet_style_require_accessibility_modifiers", - s => ParseAccessibilityModifiersRequired(s, IdeCodeStyleOptions.CommonOptions.Default.AccessibilityModifiersRequired), - v => GetAccessibilityModifiersRequiredEditorConfigString(v, IdeCodeStyleOptions.CommonOptions.Default.AccessibilityModifiersRequired)), - new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.RequireAccessibilityModifiers")); - - internal static readonly PerLanguageOption2> PreferReadonly = CreateOption( - CodeStyleOptionGroups.Field, nameof(PreferReadonly), - IdeCodeStyleOptions.CommonOptions.Default.PreferReadonly, - "dotnet_style_readonly_field", - "TextEditor.%LANGUAGE%.Specific.PreferReadonly"); - - internal static readonly Option2 FileHeaderTemplate = CreateCommonOption( - CodeStyleOptionGroups.Usings, nameof(FileHeaderTemplate), - DocumentFormattingOptions.Default.FileHeaderTemplate, - EditorConfigStorageLocation.ForStringOption("file_header_template", emptyStringRepresentation: "unset")); - - internal static readonly Option2 RemoveUnnecessarySuppressionExclusions = CreateCommonOption( - CodeStyleOptionGroups.Suppressions, - nameof(RemoveUnnecessarySuppressionExclusions), - IdeCodeStyleOptions.CommonOptions.Default.RemoveUnnecessarySuppressionExclusions, - EditorConfigStorageLocation.ForStringOption("dotnet_remove_unnecessary_suppression_exclusions", emptyStringRepresentation: "none"), - new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.RemoveUnnecessarySuppressionExclusions")); + defaultValue => new( + parseValue: str => + { + if (CodeStyleHelpers.TryGetCodeStyleValueAndOptionalNotification(str, defaultValue.Notification, out var value, out var notification)) + { + return new CodeStyleOption2(s_unusedParametersPreferenceMap.GetValueOrDefault(value), notification); + } + + return defaultValue; + }, + serializeValue: option => + { + Debug.Assert(s_unusedParametersPreferenceMap.ContainsValue(option.Value)); + var value = s_unusedParametersPreferenceMap.GetKeyOrDefault(option.Value) ?? s_unusedParametersPreferenceMap.GetKeyOrDefault(defaultValue.Value); + return $"{value}{CodeStyleHelpers.GetEditorConfigStringNotificationPart(option, defaultValue)}"; + })); private static readonly BidirectionalMap s_accessibilityModifiersRequiredMap = new(new[] @@ -279,77 +205,93 @@ private static PerLanguageOption2> CreateQualifyAccessOpt KeyValuePairUtil.Create("omit_if_default", CodeStyle.AccessibilityModifiersRequired.OmitIfDefault), }); - private static CodeStyleOption2 ParseAccessibilityModifiersRequired(string optionString, CodeStyleOption2 defaultValue) - { - if (TryGetCodeStyleValueAndOptionalNotification(optionString, - defaultValue.Notification, out var value, out var notificationOpt)) + internal static readonly PerLanguageOption2> AccessibilityModifiersRequired = CreatePerLanguageOption( + CodeStyleOptionGroups.Modifier, "dotnet_style_require_accessibility_modifiers", + IdeCodeStyleOptions.CommonOptions.Default.AccessibilityModifiersRequired, + defaultValue => new( + parseValue: str => + { + if (CodeStyleHelpers.TryGetCodeStyleValueAndOptionalNotification(str, defaultValue.Notification, out var value, out var notificationOpt)) + { + Debug.Assert(s_accessibilityModifiersRequiredMap.ContainsKey(value)); + return new CodeStyleOption2(s_accessibilityModifiersRequiredMap.GetValueOrDefault(value), notificationOpt); + } + + return defaultValue; + }, + serializeValue: option => + { + Debug.Assert(s_accessibilityModifiersRequiredMap.ContainsValue(option.Value)); + return $"{s_accessibilityModifiersRequiredMap.GetKeyOrDefault(option.Value)}{CodeStyleHelpers.GetEditorConfigStringNotificationPart(option, defaultValue)}"; + })); + + internal static readonly PerLanguageOption2> PreferReadonly = CreatePerLanguageOption( + CodeStyleOptionGroups.Field, + "dotnet_style_readonly_field", + IdeCodeStyleOptions.CommonOptions.Default.PreferReadonly); + + internal static readonly Option2 FileHeaderTemplate = CreateOption( + CodeStyleOptionGroups.Usings, + "file_header_template", + DocumentFormattingOptions.Default.FileHeaderTemplate, + EditorConfigValueSerializer.String(emptyStringRepresentation: "unset")); + + internal static readonly Option2 RemoveUnnecessarySuppressionExclusions = CreateOption( + CodeStyleOptionGroups.Suppressions, + "dotnet_remove_unnecessary_suppression_exclusions", + IdeCodeStyleOptions.CommonOptions.Default.RemoveUnnecessarySuppressionExclusions, + EditorConfigValueSerializer.String(emptyStringRepresentation: "none")); + + private static readonly BidirectionalMap s_parenthesesPreferenceMap = + new(new[] { - Debug.Assert(s_accessibilityModifiersRequiredMap.ContainsKey(value)); - return new CodeStyleOption2(s_accessibilityModifiersRequiredMap.GetValueOrDefault(value), notificationOpt); - } - - return defaultValue; - } - - private static string GetAccessibilityModifiersRequiredEditorConfigString(CodeStyleOption2 option, CodeStyleOption2 defaultValue) - { - Debug.Assert(s_accessibilityModifiersRequiredMap.ContainsValue(option.Value)); - return $"{s_accessibilityModifiersRequiredMap.GetKeyOrDefault(option.Value)}{GetEditorConfigStringNotificationPart(option, defaultValue)}"; - } - - private static PerLanguageOption2> CreateParenthesesOption( - string fieldName, CodeStyleOption2 defaultValue, - string styleName) - { - return CreateOption( - CodeStyleOptionGroups.Parentheses, fieldName, defaultValue, - new EditorConfigStorageLocation>( - styleName, - s => ParseParenthesesPreference(s, defaultValue), - v => GetParenthesesPreferenceEditorConfigString(v, defaultValue)), - new RoamingProfileStorageLocation($"TextEditor.%LANGUAGE%.Specific.{fieldName}Preference")); - } + KeyValuePairUtil.Create("always_for_clarity", ParenthesesPreference.AlwaysForClarity), + KeyValuePairUtil.Create("never_if_unnecessary", ParenthesesPreference.NeverIfUnnecessary), + }); + + private static PerLanguageOption2> CreateParenthesesOption(CodeStyleOption2 defaultValue, string name) + => CreatePerLanguageOption( + CodeStyleOptionGroups.Parentheses, + name, + defaultValue, + defaultValue => new( + parseValue: str => + { + if (CodeStyleHelpers.TryGetCodeStyleValueAndOptionalNotification(str, defaultValue.Notification, out var value, out var notification)) + { + Debug.Assert(s_parenthesesPreferenceMap.ContainsKey(value)); + return new CodeStyleOption2(s_parenthesesPreferenceMap.GetValueOrDefault(value), notification); + } + + return defaultValue; + }, + serializeValue: option => + { + Debug.Assert(s_parenthesesPreferenceMap.ContainsValue(option.Value)); + var value = s_parenthesesPreferenceMap.GetKeyOrDefault(option.Value) ?? s_parenthesesPreferenceMap.GetKeyOrDefault(ParenthesesPreference.AlwaysForClarity); + return $"{value}{CodeStyleHelpers.GetEditorConfigStringNotificationPart(option, defaultValue)}"; + })); internal static readonly PerLanguageOption2> ArithmeticBinaryParentheses = CreateParenthesesOption( - nameof(ArithmeticBinaryParentheses), IdeCodeStyleOptions.CommonOptions.Default.ArithmeticBinaryParentheses, "dotnet_style_parentheses_in_arithmetic_binary_operators"); internal static readonly PerLanguageOption2> OtherBinaryParentheses = CreateParenthesesOption( - nameof(OtherBinaryParentheses), IdeCodeStyleOptions.CommonOptions.Default.OtherBinaryParentheses, "dotnet_style_parentheses_in_other_binary_operators"); internal static readonly PerLanguageOption2> RelationalBinaryParentheses = CreateParenthesesOption( - nameof(RelationalBinaryParentheses), IdeCodeStyleOptions.CommonOptions.Default.RelationalBinaryParentheses, "dotnet_style_parentheses_in_relational_binary_operators"); internal static readonly PerLanguageOption2> OtherParentheses = CreateParenthesesOption( - nameof(OtherParentheses), IdeCodeStyleOptions.CommonOptions.Default.OtherParentheses, "dotnet_style_parentheses_in_other_operators"); - private static readonly BidirectionalMap s_parenthesesPreferenceMap = - new(new[] - { - KeyValuePairUtil.Create("always_for_clarity", ParenthesesPreference.AlwaysForClarity), - KeyValuePairUtil.Create("never_if_unnecessary", ParenthesesPreference.NeverIfUnnecessary), - }); - - private static readonly BidirectionalMap s_unusedParametersPreferenceMap = - new(new[] - { - KeyValuePairUtil.Create("non_public", UnusedParametersPreference.NonPublicMethods), - KeyValuePairUtil.Create("all", UnusedParametersPreference.AllMethods), - }); - - #region dotnet_style_prefer_foreach_explicit_cast_in_source - private static readonly BidirectionalMap s_forEachExplicitCastInSourcePreferencePreferenceMap = new(new[] { @@ -357,123 +299,66 @@ private static PerLanguageOption2> Creat KeyValuePairUtil.Create("when_strongly_typed", ForEachExplicitCastInSourcePreference.WhenStronglyTyped), }); - internal static readonly Option2> ForEachExplicitCastInSource = - CreateCommonOption( - CodeStyleOptionGroups.ExpressionLevelPreferences, - nameof(ForEachExplicitCastInSource), - IdeCodeStyleOptions.CommonOptions.Default.ForEachExplicitCastInSource, - new EditorConfigStorageLocation>( - "dotnet_style_prefer_foreach_explicit_cast_in_source", - s => ParseForEachExplicitCastInSourcePreference(s, IdeCodeStyleOptions.CommonOptions.Default.ForEachExplicitCastInSource), - v => GetForEachExplicitCastInSourceEditorConfigString(v, IdeCodeStyleOptions.CommonOptions.Default.ForEachExplicitCastInSource))); - - private static CodeStyleOption2 ParseForEachExplicitCastInSourcePreference( - string optionString, CodeStyleOption2 defaultValue) - { - if (TryGetCodeStyleValueAndOptionalNotification(optionString, - defaultValue.Notification, out var value, out var notification)) - { - Debug.Assert(s_forEachExplicitCastInSourcePreferencePreferenceMap.ContainsKey(value)); - return new CodeStyleOption2( - s_forEachExplicitCastInSourcePreferencePreferenceMap.GetValueOrDefault(value), notification); - } - - return defaultValue; - } - - private static string GetForEachExplicitCastInSourceEditorConfigString( - CodeStyleOption2 option, - CodeStyleOption2 defaultValue) - { - Debug.Assert(s_forEachExplicitCastInSourcePreferencePreferenceMap.ContainsValue(option.Value)); - var value = s_forEachExplicitCastInSourcePreferencePreferenceMap.GetKeyOrDefault(option.Value) ?? - s_forEachExplicitCastInSourcePreferencePreferenceMap.GetKeyOrDefault(defaultValue.Value); - return $"{value}{GetEditorConfigStringNotificationPart(option, defaultValue)}"; - } - - #endregion - - internal static readonly PerLanguageOption2> PreferSystemHashCode = CreateOption( + internal static readonly Option2> ForEachExplicitCastInSource = CreateOption( CodeStyleOptionGroups.ExpressionLevelPreferences, - nameof(PreferSystemHashCode), + "dotnet_style_prefer_foreach_explicit_cast_in_source", + IdeCodeStyleOptions.CommonOptions.Default.ForEachExplicitCastInSource, + defaultValue => new( + parseValue: str => + { + if (CodeStyleHelpers.TryGetCodeStyleValueAndOptionalNotification(str, defaultValue.Notification, out var value, out var notification)) + { + Debug.Assert(s_forEachExplicitCastInSourcePreferencePreferenceMap.ContainsKey(value)); + return new CodeStyleOption2( + s_forEachExplicitCastInSourcePreferencePreferenceMap.GetValueOrDefault(value), notification); + } + + return defaultValue; + }, + serializeValue: option => + { + Debug.Assert(s_forEachExplicitCastInSourcePreferencePreferenceMap.ContainsValue(option.Value)); + var value = s_forEachExplicitCastInSourcePreferencePreferenceMap.GetKeyOrDefault(option.Value) ?? + s_forEachExplicitCastInSourcePreferencePreferenceMap.GetKeyOrDefault(defaultValue.Value); + return $"{value}{CodeStyleHelpers.GetEditorConfigStringNotificationPart(option, defaultValue)}"; + })); + + internal static readonly PerLanguageOption2> PreferSystemHashCode = new( + "CodeStyleOptions_PreferSystemHashCode", IdeAnalyzerOptions.CommonDefault.PreferSystemHashCode, - new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.PreferSystemHashCode")); + group: CodeStyleOptionGroups.ExpressionLevelPreferences); - public static readonly PerLanguageOption2> PreferNamespaceAndFolderMatchStructure = CreateOption( - CodeStyleOptionGroups.ExpressionLevelPreferences, nameof(PreferNamespaceAndFolderMatchStructure), - IdeCodeStyleOptions.CommonOptions.Default.PreferNamespaceAndFolderMatchStructure, - editorconfigKeyName: "dotnet_style_namespace_match_folder", - roamingProfileStorageKeyName: "TextEditor.%LANGUAGE%.Specific.PreferNamespaceAndFolderMatchStructure"); + public static readonly PerLanguageOption2> PreferNamespaceAndFolderMatchStructure = CreatePerLanguageOption( + CodeStyleOptionGroups.ExpressionLevelPreferences, + "dotnet_style_namespace_match_folder", + IdeCodeStyleOptions.CommonOptions.Default.PreferNamespaceAndFolderMatchStructure); - internal static readonly PerLanguageOption2> AllowMultipleBlankLines = CreateOption( - CodeStyleOptionGroups.NewLinePreferences, nameof(AllowMultipleBlankLines), - IdeCodeStyleOptions.CommonOptions.Default.AllowMultipleBlankLines, + internal static readonly PerLanguageOption2> AllowMultipleBlankLines = CreatePerLanguageOption( + CodeStyleOptionGroups.NewLinePreferences, "dotnet_style_allow_multiple_blank_lines_experimental", - "TextEditor.%LANGUAGE%.Specific.AllowMultipleBlankLines"); + IdeCodeStyleOptions.CommonOptions.Default.AllowMultipleBlankLines); - internal static readonly PerLanguageOption2> AllowStatementImmediatelyAfterBlock = CreateOption( - CodeStyleOptionGroups.NewLinePreferences, nameof(AllowStatementImmediatelyAfterBlock), - IdeCodeStyleOptions.CommonOptions.Default.AllowStatementImmediatelyAfterBlock, + internal static readonly PerLanguageOption2> AllowStatementImmediatelyAfterBlock = CreatePerLanguageOption( + CodeStyleOptionGroups.NewLinePreferences, "dotnet_style_allow_statement_immediately_after_block_experimental", - "TextEditor.%LANGUAGE%.Specific.AllowStatementImmediatelyAfterBlock"); - - static CodeStyleOptions2() - { - // Note that the static constructor executes after all the static field initializers for the options have executed, - // and each field initializer adds the created option to s_allOptionsBuilder. - AllOptions = s_allOptionsBuilder.ToImmutable(); - } - - private static CodeStyleOption2 ParseParenthesesPreference( - string optionString, CodeStyleOption2 defaultValue) - { - if (TryGetCodeStyleValueAndOptionalNotification(optionString, - defaultValue.Notification, out var value, out var notification)) - { - Debug.Assert(s_parenthesesPreferenceMap.ContainsKey(value)); - return new CodeStyleOption2(s_parenthesesPreferenceMap.GetValueOrDefault(value), notification); - } - - return defaultValue; - } - - private static string GetParenthesesPreferenceEditorConfigString(CodeStyleOption2 option, CodeStyleOption2 defaultValue) - { - Debug.Assert(s_parenthesesPreferenceMap.ContainsValue(option.Value)); - var value = s_parenthesesPreferenceMap.GetKeyOrDefault(option.Value) ?? s_parenthesesPreferenceMap.GetKeyOrDefault(ParenthesesPreference.AlwaysForClarity); - return $"{value}{GetEditorConfigStringNotificationPart(option, defaultValue)}"; - } - - private static CodeStyleOption2 ParseUnusedParametersPreference(string optionString, CodeStyleOption2 defaultValue) - { - if (TryGetCodeStyleValueAndOptionalNotification(optionString, - defaultValue.Notification, out var value, out var notification)) - { - return new CodeStyleOption2(s_unusedParametersPreferenceMap.GetValueOrDefault(value), notification); - } - - return defaultValue; - } - - private static string GetUnusedParametersPreferenceEditorConfigString(CodeStyleOption2 option, CodeStyleOption2 defaultValue) - { - Debug.Assert(s_unusedParametersPreferenceMap.ContainsValue(option.Value)); - var value = s_unusedParametersPreferenceMap.GetKeyOrDefault(option.Value) ?? s_unusedParametersPreferenceMap.GetKeyOrDefault(defaultValue.Value); - return $"{value}{GetEditorConfigStringNotificationPart(option, defaultValue)}"; - } + IdeCodeStyleOptions.CommonOptions.Default.AllowStatementImmediatelyAfterBlock); + + internal static readonly ImmutableArray AllOptions = s_allOptionsBuilder.ToImmutable(); } internal static class CodeStyleOptionGroups { - public static readonly OptionGroup Usings = new(CompilerExtensionsResources.Organize_usings, priority: 1); - public static readonly OptionGroup ThisOrMe = new(CompilerExtensionsResources.this_dot_and_Me_dot_preferences, priority: 2); - public static readonly OptionGroup PredefinedTypeNameUsage = new(CompilerExtensionsResources.Language_keywords_vs_BCL_types_preferences, priority: 3); - public static readonly OptionGroup Parentheses = new(CompilerExtensionsResources.Parentheses_preferences, priority: 4); - public static readonly OptionGroup Modifier = new(CompilerExtensionsResources.Modifier_preferences, priority: 5); - public static readonly OptionGroup ExpressionLevelPreferences = new(CompilerExtensionsResources.Expression_level_preferences, priority: 6); - public static readonly OptionGroup Field = new(CompilerExtensionsResources.Field_preferences, priority: 7); - public static readonly OptionGroup Parameter = new(CompilerExtensionsResources.Parameter_preferences, priority: 8); - public static readonly OptionGroup Suppressions = new(CompilerExtensionsResources.Suppression_preferences, priority: 9); - public static readonly OptionGroup NewLinePreferences = new(CompilerExtensionsResources.New_line_preferences, priority: 10); + public static readonly OptionGroup CodeStyle = new("", priority: 1); + + public static readonly OptionGroup Usings = new(CompilerExtensionsResources.Organize_usings, priority: 1, parent: CodeStyle); + public static readonly OptionGroup ThisOrMe = new(CompilerExtensionsResources.this_dot_and_Me_dot_preferences, priority: 2, parent: CodeStyle); + public static readonly OptionGroup PredefinedTypeNameUsage = new(CompilerExtensionsResources.Language_keywords_vs_BCL_types_preferences, priority: 3, parent: CodeStyle); + public static readonly OptionGroup Parentheses = new(CompilerExtensionsResources.Parentheses_preferences, priority: 4, parent: CodeStyle); + public static readonly OptionGroup Modifier = new(CompilerExtensionsResources.Modifier_preferences, priority: 5, parent: CodeStyle); + public static readonly OptionGroup ExpressionLevelPreferences = new(CompilerExtensionsResources.Expression_level_preferences, priority: 6, parent: CodeStyle); + public static readonly OptionGroup Field = new(CompilerExtensionsResources.Field_preferences, priority: 7, parent: CodeStyle); + public static readonly OptionGroup Parameter = new(CompilerExtensionsResources.Parameter_preferences, priority: 8, parent: CodeStyle); + public static readonly OptionGroup Suppressions = new(CompilerExtensionsResources.Suppression_preferences, priority: 9, parent: CodeStyle); + public static readonly OptionGroup NewLinePreferences = new(CompilerExtensionsResources.New_line_preferences, priority: 10, parent: CodeStyle); } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/FadingOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/FadingOptions.cs index 04b370e2f1812..27f3f8c819801 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/FadingOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/FadingOptions.cs @@ -9,12 +9,7 @@ namespace Microsoft.CodeAnalysis.CodeStyle { internal static class FadingOptions { - public static readonly PerLanguageOption2 FadeOutUnusedImports = new( - "FadingOptions", "FadeOutUnusedImports", defaultValue: true, - storageLocation: new RoamingProfileStorageLocation($"TextEditor.%LANGUAGE%.Specific.FadeOutUnusedImports")); - - public static readonly PerLanguageOption2 FadeOutUnreachableCode = new( - "FadingOptions", "FadeOutUnreachableCode", defaultValue: true, - storageLocation: new RoamingProfileStorageLocation($"TextEditor.%LANGUAGE%.Specific.FadeOutUnreachableCode")); + public static readonly PerLanguageOption2 FadeOutUnusedImports = new("FadingOptions_FadeOutUnusedImports", defaultValue: true); + public static readonly PerLanguageOption2 FadeOutUnreachableCode = new("FadingOptions_FadeOutUnreachableCode", defaultValue: true); } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/IdeCodeStyleOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/IdeCodeStyleOptions.cs index 6ec140dba0c28..10c0ffb51fa9a 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/IdeCodeStyleOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/IdeCodeStyleOptions.cs @@ -5,9 +5,12 @@ using System.Runtime.Serialization; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Options; +#if !CODE_STYLE +using Microsoft.CodeAnalysis.Host; +#endif + namespace Microsoft.CodeAnalysis.CodeStyle; internal abstract class IdeCodeStyleOptions @@ -75,3 +78,42 @@ public static IdeCodeStyleOptions GetDefault(LanguageServices languageServices) => languageServices.GetRequiredService().DefaultOptions; #endif } + +internal static class IdeCodeStyleOptionsProviders +{ + public static IdeCodeStyleOptions.CommonOptions GetCommonCodeStyleOptions(this IOptionsReader options, string language, IdeCodeStyleOptions.CommonOptions? fallbackOptions) + { + fallbackOptions ??= IdeCodeStyleOptions.CommonOptions.Default; + + return new() + { + PreferObjectInitializer = options.GetOption(CodeStyleOptions2.PreferObjectInitializer, language, fallbackOptions.PreferObjectInitializer), + PreferCollectionInitializer = options.GetOption(CodeStyleOptions2.PreferCollectionInitializer, language, fallbackOptions.PreferCollectionInitializer), + PreferSimplifiedBooleanExpressions = options.GetOption(CodeStyleOptions2.PreferSimplifiedBooleanExpressions, language, fallbackOptions.PreferSimplifiedBooleanExpressions), + OperatorPlacementWhenWrapping = options.GetOption(CodeStyleOptions2.OperatorPlacementWhenWrapping, fallbackOptions.OperatorPlacementWhenWrapping), + PreferCoalesceExpression = options.GetOption(CodeStyleOptions2.PreferCoalesceExpression, language, fallbackOptions.PreferCoalesceExpression), + PreferNullPropagation = options.GetOption(CodeStyleOptions2.PreferNullPropagation, language, fallbackOptions.PreferNullPropagation), + PreferExplicitTupleNames = options.GetOption(CodeStyleOptions2.PreferExplicitTupleNames, language, fallbackOptions.PreferExplicitTupleNames), + PreferAutoProperties = options.GetOption(CodeStyleOptions2.PreferAutoProperties, language, fallbackOptions.PreferAutoProperties), + PreferInferredTupleNames = options.GetOption(CodeStyleOptions2.PreferInferredTupleNames, language, fallbackOptions.PreferInferredTupleNames), + PreferInferredAnonymousTypeMemberNames = options.GetOption(CodeStyleOptions2.PreferInferredAnonymousTypeMemberNames, language, fallbackOptions.PreferInferredAnonymousTypeMemberNames), + PreferIsNullCheckOverReferenceEqualityMethod = options.GetOption(CodeStyleOptions2.PreferIsNullCheckOverReferenceEqualityMethod, language, fallbackOptions.PreferIsNullCheckOverReferenceEqualityMethod), + PreferConditionalExpressionOverAssignment = options.GetOption(CodeStyleOptions2.PreferConditionalExpressionOverAssignment, language, fallbackOptions.PreferConditionalExpressionOverAssignment), + PreferConditionalExpressionOverReturn = options.GetOption(CodeStyleOptions2.PreferConditionalExpressionOverReturn, language, fallbackOptions.PreferConditionalExpressionOverReturn), + PreferCompoundAssignment = options.GetOption(CodeStyleOptions2.PreferCompoundAssignment, language, fallbackOptions.PreferCompoundAssignment), + PreferSimplifiedInterpolation = options.GetOption(CodeStyleOptions2.PreferSimplifiedInterpolation, language, fallbackOptions.PreferSimplifiedInterpolation), + UnusedParameters = options.GetOption(CodeStyleOptions2.UnusedParameters, language, fallbackOptions.UnusedParameters), + AccessibilityModifiersRequired = options.GetOption(CodeStyleOptions2.AccessibilityModifiersRequired, language, fallbackOptions.AccessibilityModifiersRequired), + PreferReadonly = options.GetOption(CodeStyleOptions2.PreferReadonly, language, fallbackOptions.PreferReadonly), + ArithmeticBinaryParentheses = options.GetOption(CodeStyleOptions2.ArithmeticBinaryParentheses, language, fallbackOptions.ArithmeticBinaryParentheses), + OtherBinaryParentheses = options.GetOption(CodeStyleOptions2.OtherBinaryParentheses, language, fallbackOptions.OtherBinaryParentheses), + RelationalBinaryParentheses = options.GetOption(CodeStyleOptions2.RelationalBinaryParentheses, language, fallbackOptions.RelationalBinaryParentheses), + OtherParentheses = options.GetOption(CodeStyleOptions2.OtherParentheses, language, fallbackOptions.OtherParentheses), + ForEachExplicitCastInSource = options.GetOption(CodeStyleOptions2.ForEachExplicitCastInSource, fallbackOptions.ForEachExplicitCastInSource), + PreferNamespaceAndFolderMatchStructure = options.GetOption(CodeStyleOptions2.PreferNamespaceAndFolderMatchStructure, language, fallbackOptions.PreferNamespaceAndFolderMatchStructure), + AllowMultipleBlankLines = options.GetOption(CodeStyleOptions2.AllowMultipleBlankLines, language, fallbackOptions.AllowMultipleBlankLines), + AllowStatementImmediatelyAfterBlock = options.GetOption(CodeStyleOptions2.AllowStatementImmediatelyAfterBlock, language, fallbackOptions.AllowStatementImmediatelyAfterBlock), + RemoveUnnecessarySuppressionExclusions = options.GetOption(CodeStyleOptions2.RemoveUnnecessarySuppressionExclusions, fallbackOptions.RemoveUnnecessarySuppressionExclusions) + }; + } +} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/OperatorPlacementWhenWrappingPreference.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/OperatorPlacementWhenWrappingPreference.cs index 58cb40b7b0aef..9866152565b2e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/OperatorPlacementWhenWrappingPreference.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/OperatorPlacementWhenWrappingPreference.cs @@ -19,7 +19,7 @@ internal static class OperatorPlacementUtilities public static string GetEditorConfigString(OperatorPlacementWhenWrappingPreference value) => value == OperatorPlacementWhenWrappingPreference.EndOfLine ? end_of_line : beginning_of_line; - public static Optional Parse(string optionString) + public static Optional Parse(string optionString, OperatorPlacementWhenWrappingPreference defaultValue) { if (CodeStyleHelpers.TryGetCodeStyleValue(optionString, out var value)) { @@ -30,8 +30,7 @@ public static Optional Parse(string opt } } - // Default to beginning_of_line if we get something we don't understand. - return OperatorPlacementWhenWrappingPreference.BeginningOfLine; + return defaultValue; } } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems index 471d82cb737d5..35d6a13ea3e33 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems @@ -254,6 +254,10 @@ + + + + @@ -385,23 +389,15 @@ - - - - - + + + - - - - - - + - @@ -464,6 +460,7 @@ + @@ -542,7 +539,6 @@ - diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Diagnostics/IdeAnalyzerOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Diagnostics/IdeAnalyzerOptions.cs index 3f13eb7deb333..4b3dfa529a388 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Diagnostics/IdeAnalyzerOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Diagnostics/IdeAnalyzerOptions.cs @@ -6,7 +6,10 @@ using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CodeStyle; + +#if !CODE_STYLE using Microsoft.CodeAnalysis.Host; +#endif namespace Microsoft.CodeAnalysis.Diagnostics; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Diagnostics/StructuredAnalyzerConfigOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Diagnostics/StructuredAnalyzerConfigOptions.cs index f0af2b45485d0..76b0896a974b6 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Diagnostics/StructuredAnalyzerConfigOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Diagnostics/StructuredAnalyzerConfigOptions.cs @@ -9,6 +9,7 @@ using System.Reflection; using System.Runtime.CompilerServices; using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; +using Microsoft.CodeAnalysis.Options; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Diagnostics; @@ -17,7 +18,7 @@ namespace Microsoft.CodeAnalysis.Diagnostics; /// that memoize structured (parsed) form of certain complex options to avoid parsing them multiple times. /// Storages of these complex options may directly call the specialized getters to reuse the cached values. /// -internal abstract class StructuredAnalyzerConfigOptions : AnalyzerConfigOptions +internal abstract class StructuredAnalyzerConfigOptions : AnalyzerConfigOptions, IOptionsReader { internal sealed class Implementation : StructuredAnalyzerConfigOptions { @@ -68,6 +69,9 @@ public static StructuredAnalyzerConfigOptions Create(ImmutableDictionary new Implementation(options); + public bool TryGetOption(OptionKey2 optionKey, out T value) + => this.TryGetEditorConfigOption(optionKey.Option, out value); + public static bool TryGetStructuredOptions(AnalyzerConfigOptions configOptions, [NotNullWhen(true)] out StructuredAnalyzerConfigOptions? options) { if (configOptions is StructuredAnalyzerConfigOptions structuredOptions) @@ -88,7 +92,7 @@ public static bool TryGetStructuredOptions(AnalyzerConfigOptions configOptions, } #if CODE_STYLE - // StructuredAnalyzerConfigOptions is defined in both Worksapce and Code Style layers. It is not public and thus can't be shared between these two. + // StructuredAnalyzerConfigOptions is defined in both Workspace and Code Style layers. It is not public and thus can't be shared between these two. // However, Code Style layer is compiled against the shared Workspace APIs. The ProjectState creates and holds onto an instance // of Workspace layer's version of StructuredAnalyzerConfigOptions. This version of the type is not directly usable by Code Style code. // We create a clone of this instance typed to the Code Style's version of StructuredAnalyzerConfigOptions. diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Editing/GenerationOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Editing/GenerationOptions.cs index a06292979c330..13cb4d642a4cd 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Editing/GenerationOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Editing/GenerationOptions.cs @@ -13,16 +13,16 @@ namespace Microsoft.CodeAnalysis.Editing internal class GenerationOptions { public static readonly PerLanguageOption2 PlaceSystemNamespaceFirst = new( - "GenerationOptions", CodeStyleOptionGroups.Usings, "PlaceSystemNamespaceFirst", - AddImportPlacementOptions.Default.PlaceSystemNamespaceFirst, - EditorConfigStorageLocation.ForBoolOption("dotnet_sort_system_directives_first"), - new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.PlaceSystemNamespaceFirst")); + "dotnet_sort_system_directives_first", + defaultValue: AddImportPlacementOptions.Default.PlaceSystemNamespaceFirst, + group: CodeStyleOptionGroups.Usings, + isEditorConfigOption: true); public static readonly PerLanguageOption2 SeparateImportDirectiveGroups = new( - "GenerationOptions", CodeStyleOptionGroups.Usings, "SeparateImportDirectiveGroups", - SyntaxFormattingOptions.CommonOptions.Default.SeparateImportDirectiveGroups, - EditorConfigStorageLocation.ForBoolOption("dotnet_separate_import_directive_groups"), - new RoamingProfileStorageLocation($"TextEditor.%LANGUAGE%.Specific.{nameof(SeparateImportDirectiveGroups)}")); + "dotnet_separate_import_directive_groups", + defaultValue: SyntaxFormattingOptions.CommonOptions.Default.SeparateImportDirectiveGroups, + group: CodeStyleOptionGroups.Usings, + isEditorConfigOption: true); public static readonly ImmutableArray AllOptions = ImmutableArray.Create( PlaceSystemNamespaceFirst, diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/AnalyzerConfigOptionsExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/AnalyzerConfigOptionsExtensions.cs index 31979023536ad..879ea52db5090 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/AnalyzerConfigOptionsExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/AnalyzerConfigOptionsExtensions.cs @@ -4,92 +4,56 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Linq; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; using Microsoft.CodeAnalysis.Options; using Roslyn.Utilities; -#if CODE_STYLE -using TOption = Microsoft.CodeAnalysis.Options.IOption2; -#else -using TOption = Microsoft.CodeAnalysis.Options.IOption; -#endif - namespace Microsoft.CodeAnalysis { internal static class AnalyzerConfigOptionsExtensions { - public static T GetOption(this AnalyzerConfigOptions analyzerConfigOptions, Option2 option) - => GetOptionWithAssertOnFailure(analyzerConfigOptions, option); + public static T GetEditorConfigOption(this AnalyzerConfigOptions analyzerConfigOptions, IOption2 option, T defaultValue) + => TryGetEditorConfigOption(analyzerConfigOptions, option, out var value) ? value! : defaultValue; - public static T GetOption(this AnalyzerConfigOptions analyzerConfigOptions, PerLanguageOption2 option) - => GetOptionWithAssertOnFailure(analyzerConfigOptions, option); + public static T GetEditorConfigOptionValue(this AnalyzerConfigOptions analyzerConfigOptions, IOption2 option, T defaultValue) + => TryGetEditorConfigOption>(analyzerConfigOptions, option, out var style) ? style!.Value : defaultValue; - private static T GetOptionWithAssertOnFailure(AnalyzerConfigOptions analyzerConfigOptions, TOption option) + public static bool TryGetEditorConfigOption(this AnalyzerConfigOptions analyzerConfigOptions, IOption2 option, out T value) { - if (!TryGetEditorConfigOptionOrDefault(analyzerConfigOptions, option, out T value)) - { - // There are couple of reasons this assert might fire: - // 1. Attempting to access an option which does not have an IEditorConfigStorageLocation. - // 2. Attempting to access an option which is not exposed from any option provider, i.e. IOptionProvider.Options. - Debug.Fail("Failed to find a .editorconfig key for the option."); - value = (T)option.DefaultValue!; - } - - return value; - } - - private static bool TryGetEditorConfigOptionOrDefault(this AnalyzerConfigOptions analyzerConfigOptions, TOption option, out T value) - => TryGetEditorConfigOption(analyzerConfigOptions, option, (T?)option.DefaultValue, out value!); + Contract.ThrowIfFalse(option.Definition.IsEditorConfigOption); - public static bool TryGetEditorConfigOption(this AnalyzerConfigOptions analyzerConfigOptions, TOption option, [MaybeNullWhen(false)] out T value) - => TryGetEditorConfigOption(analyzerConfigOptions, option, defaultValue: default, out value); - - public static T GetEditorConfigOption(this AnalyzerConfigOptions analyzerConfigOptions, TOption option, T defaultValue) - => TryGetEditorConfigOption(analyzerConfigOptions, option, new Optional(defaultValue), out var value) ? value! : throw ExceptionUtilities.Unreachable(); - - public static T GetEditorConfigOptionValue(this AnalyzerConfigOptions analyzerConfigOptions, TOption option, T defaultValue) - => TryGetEditorConfigOption(analyzerConfigOptions, option, new Optional?>(new CodeStyleOption2(defaultValue, NotificationOption2.None)), out var style) ? style!.Value : throw ExceptionUtilities.Unreachable(); - - private static bool TryGetEditorConfigOption(this AnalyzerConfigOptions analyzerConfigOptions, TOption option, Optional defaultValue, out T? value) - { - var hasEditorConfigStorage = false; - foreach (var storageLocation in option.StorageLocations) + if (option.Definition.Type == typeof(NamingStylePreferences)) { - // This code path will avoid allocating a Dictionary wrapper since we can get direct access to the KeyName. - if (storageLocation is EditorConfigStorageLocation editorConfigStorageLocation && - analyzerConfigOptions.TryGetValue(editorConfigStorageLocation.KeyName, out var stringValue) && - editorConfigStorageLocation.TryGetOption(stringValue, out value)) - { - return true; - } - - if (storageLocation is not IEditorConfigStorageLocation configStorageLocation) - { - continue; - } - - // This option has .editorconfig storage defined, even if the current configuration does not provide a - // value for it. - hasEditorConfigStorage = true; - if (StructuredAnalyzerConfigOptions.TryGetStructuredOptions(analyzerConfigOptions, out var structuredOptions) && - configStorageLocation.TryGetOption(structuredOptions, option.Type, out var objectValue)) + if (StructuredAnalyzerConfigOptions.TryGetStructuredOptions(analyzerConfigOptions, out var structuredOptions)) { - value = (T?)objectValue; - return true; + var preferences = structuredOptions.GetNamingStylePreferences(); + value = (T)(object)preferences; + return !preferences.IsEmpty; } } - - if (defaultValue.HasValue) - { - value = defaultValue.Value; - return hasEditorConfigStorage; - } else { - value = default; - return false; + if (analyzerConfigOptions.TryGetValue(option.Definition.ConfigName, out var stringValue)) + { + // Avoid boxing when reading typed value: + if (typeof(T) != typeof(object)) + { + return ((OptionDefinition)option.Definition).Serializer.TryParseValue(stringValue, out value!); + } + + if (option.Definition.Serializer.TryParse(stringValue, out var objectValue)) + { + value = (T)objectValue!; + return true; + } + } } + + value = default!; + return false; } } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ICompilationExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ICompilationExtensions.cs index 2babce6cbad19..fe44f41b8f339 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ICompilationExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ICompilationExtensions.cs @@ -236,5 +236,8 @@ public static ImmutableArray GetReferencedAssemblySymbols(this public static INamedTypeSymbol? ValueTupleType(this Compilation compilation, int arity) => compilation.GetTypeByMetadataName($"System.ValueTuple`{arity}"); + + public static INamedTypeSymbol? ListOfTType(this Compilation compilation) + => compilation.GetTypeByMetadataName(typeof(List<>).FullName!); } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/AbstractSyntaxFormatting.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/AbstractSyntaxFormatting.cs index 5178f7c9f4958..82aa0dd9a926b 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/AbstractSyntaxFormatting.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/AbstractSyntaxFormatting.cs @@ -9,6 +9,7 @@ using System.Threading; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Formatting.Rules; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared; using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Shared.Utilities; @@ -26,7 +27,7 @@ protected AbstractSyntaxFormatting() } public abstract SyntaxFormattingOptions DefaultOptions { get; } - public abstract SyntaxFormattingOptions GetFormattingOptions(AnalyzerConfigOptions options, SyntaxFormattingOptions? fallbackOptions); + public abstract SyntaxFormattingOptions GetFormattingOptions(IOptionsReader options, SyntaxFormattingOptions? fallbackOptions); public abstract ImmutableArray GetDefaultFormattingRules(); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/DocumentFormattingOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/DocumentFormattingOptions.cs index fadede286785c..f18a374f8e932 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/DocumentFormattingOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/DocumentFormattingOptions.cs @@ -8,6 +8,7 @@ using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.Formatting; @@ -30,14 +31,14 @@ internal interface DocumentFormattingOptionsProvider internal static class DocumentFormattingOptionsProviders { - public static DocumentFormattingOptions GetDocumentFormattingOptions(this AnalyzerConfigOptions options, DocumentFormattingOptions? fallbackOptions) + public static DocumentFormattingOptions GetDocumentFormattingOptions(this IOptionsReader options, DocumentFormattingOptions? fallbackOptions) { fallbackOptions ??= DocumentFormattingOptions.Default; return new() { - FileHeaderTemplate = options.GetEditorConfigOption(CodeStyleOptions2.FileHeaderTemplate, fallbackOptions.FileHeaderTemplate), - InsertFinalNewLine = options.GetEditorConfigOption(FormattingOptions2.InsertFinalNewLine, fallbackOptions.InsertFinalNewLine) + FileHeaderTemplate = options.GetOption(CodeStyleOptions2.FileHeaderTemplate, fallbackOptions.FileHeaderTemplate), + InsertFinalNewLine = options.GetOption(FormattingOptions2.InsertFinalNewLine, fallbackOptions.InsertFinalNewLine) }; } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/FormattingOptions2.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/FormattingOptions2.cs index fa15233725bb7..f512d87e74e70 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/FormattingOptions2.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/FormattingOptions2.cs @@ -9,10 +9,9 @@ #if CODE_STYLE using WorkspacesResources = Microsoft.CodeAnalysis.CodeStyleResources; +using PublicIndentStyle = Microsoft.CodeAnalysis.Formatting.FormattingOptions2.IndentStyle; #else -using System.Composition; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options.Providers; +using PublicIndentStyle = Microsoft.CodeAnalysis.Formatting.FormattingOptions.IndentStyle; #endif namespace Microsoft.CodeAnalysis.Formatting @@ -22,43 +21,24 @@ namespace Microsoft.CodeAnalysis.Formatting /// internal sealed partial class FormattingOptions2 { -#if !CODE_STYLE - [ExportSolutionOptionProvider, Shared] - internal sealed class Provider : IOptionProvider - { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public Provider() - { - } - - public ImmutableArray Options { get; } = FormattingOptions2.Options; - } -#endif - private const string FeatureName = "FormattingOptions"; + private const string PublicFeatureName = "FormattingOptions"; - public static PerLanguageOption2 UseTabs = - new(FeatureName, FormattingOptionGroups.IndentationAndSpacing, nameof(UseTabs), LineFormattingOptions.Default.UseTabs, - storageLocations: ImmutableArray.Create( - new EditorConfigStorageLocation("indent_style", s => s == "tab", isSet => isSet ? "tab" : "space"), - new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Insert Tabs"))); + public static PerLanguageOption2 UseTabs = new PerLanguageOption2( + "indent_style", LineFormattingOptions.Default.UseTabs, FormattingOptionGroups.IndentationAndSpacing, isEditorConfigOption: true, + serializer: new EditorConfigValueSerializer(str => str == "tab", value => value ? "tab" : "space")) + .WithPublicOption(PublicFeatureName, "UseTabs"); - public static PerLanguageOption2 TabSize = - new(FeatureName, FormattingOptionGroups.IndentationAndSpacing, nameof(TabSize), LineFormattingOptions.Default.TabSize, - storageLocations: ImmutableArray.Create( - EditorConfigStorageLocation.ForInt32Option("tab_width"), - new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Tab Size"))); + public static PerLanguageOption2 TabSize = new PerLanguageOption2( + "tab_width", LineFormattingOptions.Default.TabSize, FormattingOptionGroups.IndentationAndSpacing, isEditorConfigOption: true) + .WithPublicOption(PublicFeatureName, "TabSize"); - public static PerLanguageOption2 IndentationSize = - new(FeatureName, FormattingOptionGroups.IndentationAndSpacing, nameof(IndentationSize), LineFormattingOptions.Default.IndentationSize, - storageLocations: ImmutableArray.Create( - EditorConfigStorageLocation.ForInt32Option("indent_size"), - new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Indent Size"))); + public static PerLanguageOption2 IndentationSize = new PerLanguageOption2( + "indent_size", LineFormattingOptions.Default.IndentationSize, FormattingOptionGroups.IndentationAndSpacing, isEditorConfigOption: true) + .WithPublicOption(PublicFeatureName, "IndentationSize"); - public static PerLanguageOption2 NewLine = - new(FeatureName, FormattingOptionGroups.NewLine, nameof(NewLine), LineFormattingOptions.Default.NewLine, - storageLocation: new EditorConfigStorageLocation( - "end_of_line", + public static PerLanguageOption2 NewLine = new PerLanguageOption2( + "end_of_line", LineFormattingOptions.Default.NewLine, FormattingOptionGroups.NewLine, isEditorConfigOption: true, + serializer: new EditorConfigValueSerializer( parseValue: value => value.Trim() switch { "lf" => "\n", @@ -72,18 +52,20 @@ public Provider() "\r" => "cr", "\r\n" => "crlf", _ => "unset" - })); + })) + .WithPublicOption(PublicFeatureName, "NewLine"); - internal static Option2 InsertFinalNewLine = - new(FeatureName, FormattingOptionGroups.NewLine, nameof(InsertFinalNewLine), DocumentFormattingOptions.Default.InsertFinalNewLine, - storageLocation: EditorConfigStorageLocation.ForBoolOption("insert_final_newline")); + internal static Option2 InsertFinalNewLine = new( + "insert_final_newline", DocumentFormattingOptions.Default.InsertFinalNewLine, FormattingOptionGroups.NewLine, isEditorConfigOption: true); - public static PerLanguageOption2 SmartIndent { get; } = - new(FeatureName, FormattingOptionGroups.IndentationAndSpacing, nameof(SmartIndent), defaultValue: IndentationOptions.DefaultIndentStyle, - new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Indent Style")); + public static PerLanguageOption2 SmartIndent = new PerLanguageOption2( + "FormattingOptions_SmartIndent", + defaultValue: IndentationOptions.DefaultIndentStyle, + group: FormattingOptionGroups.IndentationAndSpacing) + .WithPublicOption(PublicFeatureName, "SmartIndent", static value => (PublicIndentStyle)value, static value => (IndentStyle)value); #if !CODE_STYLE - internal static readonly ImmutableArray Options = ImmutableArray.Create( + internal static readonly ImmutableArray Options = ImmutableArray.Create( UseTabs, TabSize, IndentationSize, diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/ISyntaxFormatting.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/ISyntaxFormatting.cs index 6301d47059ce8..ef25534b4e233 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/ISyntaxFormatting.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/ISyntaxFormatting.cs @@ -7,6 +7,7 @@ using System.Threading; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Formatting.Rules; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Formatting; @@ -14,7 +15,7 @@ namespace Microsoft.CodeAnalysis.Formatting; internal interface ISyntaxFormatting { SyntaxFormattingOptions DefaultOptions { get; } - SyntaxFormattingOptions GetFormattingOptions(AnalyzerConfigOptions options, SyntaxFormattingOptions? fallbackOptions); + SyntaxFormattingOptions GetFormattingOptions(IOptionsReader options, SyntaxFormattingOptions? fallbackOptions); ImmutableArray GetDefaultFormattingRules(); IFormattingResult GetFormattingResult(SyntaxNode node, IEnumerable? spans, SyntaxFormattingOptions options, IEnumerable? rules, CancellationToken cancellationToken); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/LineFormattingOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/LineFormattingOptions.cs index 56161a8a89286..a856c70921e94 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/LineFormattingOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/LineFormattingOptions.cs @@ -7,6 +7,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.Formatting; @@ -30,16 +31,16 @@ internal interface LineFormattingOptionsProvider internal static partial class LineFormattingOptionsProviders { - public static LineFormattingOptions GetLineFormattingOptions(this AnalyzerConfigOptions options, LineFormattingOptions? fallbackOptions) + public static LineFormattingOptions GetLineFormattingOptions(this IOptionsReader options, string language, LineFormattingOptions? fallbackOptions) { fallbackOptions ??= LineFormattingOptions.Default; return new() { - UseTabs = options.GetEditorConfigOption(FormattingOptions2.UseTabs, fallbackOptions.UseTabs), - TabSize = options.GetEditorConfigOption(FormattingOptions2.TabSize, fallbackOptions.TabSize), - IndentationSize = options.GetEditorConfigOption(FormattingOptions2.IndentationSize, fallbackOptions.IndentationSize), - NewLine = options.GetEditorConfigOption(FormattingOptions2.NewLine, fallbackOptions.NewLine), + UseTabs = options.GetOption(FormattingOptions2.UseTabs, language, fallbackOptions.UseTabs), + TabSize = options.GetOption(FormattingOptions2.TabSize, language, fallbackOptions.TabSize), + IndentationSize = options.GetOption(FormattingOptions2.IndentationSize, language, fallbackOptions.IndentationSize), + NewLine = options.GetOption(FormattingOptions2.NewLine, language, fallbackOptions.NewLine), }; } @@ -47,7 +48,7 @@ public static LineFormattingOptions GetLineFormattingOptions(this AnalyzerConfig public static async ValueTask GetLineFormattingOptionsAsync(this Document document, LineFormattingOptions? fallbackOptions, CancellationToken cancellationToken) { var configOptions = await document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); - return configOptions.GetLineFormattingOptions(fallbackOptions); + return configOptions.GetLineFormattingOptions(document.Project.Language, fallbackOptions); } public static async ValueTask GetLineFormattingOptionsAsync(this Document document, LineFormattingOptionsProvider fallbackOptionsProvider, CancellationToken cancellationToken) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/SyntaxFormattingOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/SyntaxFormattingOptions.cs index afe452f08bbee..c6260a92ce009 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/SyntaxFormattingOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/SyntaxFormattingOptions.cs @@ -8,9 +8,12 @@ using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Options; +#if !CODE_STYLE +using Microsoft.CodeAnalysis.Host; +#endif + namespace Microsoft.CodeAnalysis.Formatting; internal abstract class SyntaxFormattingOptions @@ -54,20 +57,20 @@ internal interface SyntaxFormattingOptionsProvider : internal static partial class SyntaxFormattingOptionsProviders { - public static SyntaxFormattingOptions.CommonOptions GetCommonSyntaxFormattingOptions(this AnalyzerConfigOptions options, SyntaxFormattingOptions.CommonOptions? fallbackOptions) + public static SyntaxFormattingOptions.CommonOptions GetCommonSyntaxFormattingOptions(this IOptionsReader options, string language, SyntaxFormattingOptions.CommonOptions? fallbackOptions) { fallbackOptions ??= SyntaxFormattingOptions.CommonOptions.Default; return new() { - LineFormatting = options.GetLineFormattingOptions(fallbackOptions.LineFormatting), - SeparateImportDirectiveGroups = options.GetEditorConfigOption(GenerationOptions.SeparateImportDirectiveGroups, fallbackOptions.SeparateImportDirectiveGroups), - AccessibilityModifiersRequired = options.GetEditorConfigOptionValue(CodeStyleOptions2.AccessibilityModifiersRequired, fallbackOptions.AccessibilityModifiersRequired), + LineFormatting = options.GetLineFormattingOptions(language, fallbackOptions.LineFormatting), + SeparateImportDirectiveGroups = options.GetOption(GenerationOptions.SeparateImportDirectiveGroups, language, fallbackOptions.SeparateImportDirectiveGroups), + AccessibilityModifiersRequired = options.GetOptionValue(CodeStyleOptions2.AccessibilityModifiersRequired, language, fallbackOptions.AccessibilityModifiersRequired), }; } #if !CODE_STYLE - public static SyntaxFormattingOptions GetSyntaxFormattingOptions(this AnalyzerConfigOptions options, SyntaxFormattingOptions? fallbackOptions, LanguageServices languageServices) + public static SyntaxFormattingOptions GetSyntaxFormattingOptions(this IOptionsReader options, SyntaxFormattingOptions? fallbackOptions, LanguageServices languageServices) => languageServices.GetRequiredService().GetFormattingOptions(options, fallbackOptions); public static async ValueTask GetSyntaxFormattingOptionsAsync(this Document document, SyntaxFormattingOptions? fallbackOptions, CancellationToken cancellationToken) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Indentation/IndentationOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Indentation/IndentationOptions.cs index 2262cf292ca6e..7c32cbd3ac91a 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Indentation/IndentationOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Indentation/IndentationOptions.cs @@ -4,7 +4,10 @@ using System.Runtime.Serialization; using Microsoft.CodeAnalysis.Formatting; + +#if !CODE_STYLE using Microsoft.CodeAnalysis.Host; +#endif namespace Microsoft.CodeAnalysis.Indentation { diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/NamingStyleOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/NamingStyleOptions.cs index fb0ba6a9e0f2d..a683e30c8b46b 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/NamingStyleOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/NamingStyleOptions.cs @@ -5,28 +5,26 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; -using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Options; +#if !CODE_STYLE +using Microsoft.CodeAnalysis.Host; +#endif + namespace Microsoft.CodeAnalysis.CodeStyle { internal static class NamingStyleOptions { - // Use 'SimplificationOptions' for back compat as the below option 'NamingPreferences' was defined with feature name 'SimplificationOptions'. - private const string FeatureName = "SimplificationOptions"; + public const string NamingPreferencesOptionName = "SimplificationOptions_NamingPreferences"; /// /// This option describes the naming rules that should be applied to specified categories of symbols, /// and the level to which those rules should be enforced. /// - internal static PerLanguageOption2 NamingPreferences { get; } = new PerLanguageOption2( - FeatureName, nameof(NamingPreferences), defaultValue: NamingStylePreferences.Default, - new NamingStylePreferenceEditorConfigStorageLocation(), - new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.NamingPreferences5"), - new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.NamingPreferences")); - - public static OptionKey2 GetNamingPreferencesOptionKey(string language) - => new(NamingPreferences, language); + internal static PerLanguageOption2 NamingPreferences { get; } = new( + NamingPreferencesOptionName, + defaultValue: NamingStylePreferences.Default, + isEditorConfigOption: true); } internal interface NamingStylePreferencesProvider diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/ClientSettingsStorageLocation.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/ClientSettingsStorageLocation.cs deleted file mode 100644 index 3d12ba03c3427..0000000000000 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/ClientSettingsStorageLocation.cs +++ /dev/null @@ -1,49 +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 Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.Options; - -/// -/// Specifies that the option is stored in setting storage of the client. -/// -/// -/// TODO (https://github.com/dotnet/roslyn/issues/62683): The options that use this storage are global client options. -/// This storage should really be in the VS layer but currently option storage is coupled with option definition and thus the storage is needed here. -/// -internal abstract class ClientSettingsStorageLocation : OptionStorageLocation2 -{ - private readonly Func _keyNameFromLanguageName; - - public ClientSettingsStorageLocation(string keyName) - => _keyNameFromLanguageName = _ => keyName; - - /// - /// Creates a that has different key names for different languages. - /// - /// A function that maps from a value to the key name. - public ClientSettingsStorageLocation(Func keyNameFromLanguageName) - => _keyNameFromLanguageName = keyNameFromLanguageName; - - public abstract bool IsMachineLocal { get; } - - public string GetKeyNameForLanguage(string? languageName) - { - var keyName = _keyNameFromLanguageName(languageName); - - if (languageName != null) - { - keyName = keyName.Replace("%LANGUAGE%", languageName switch - { - LanguageNames.CSharp => "CSharp", - LanguageNames.VisualBasic => "VisualBasic", - _ => languageName // handles F#, TypeScript and Xaml - }); - } - - return keyName; - } -} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/EditorConfig/EditorConfigStorageLocation.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/EditorConfig/EditorConfigStorageLocation.cs deleted file mode 100644 index 2fd26e4d3dbe7..0000000000000 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/EditorConfig/EditorConfigStorageLocation.cs +++ /dev/null @@ -1,65 +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 Microsoft.CodeAnalysis.CodeStyle; - -namespace Microsoft.CodeAnalysis.Options -{ - internal static class EditorConfigStorageLocation - { - public static EditorConfigStorageLocation ForBoolOption(string keyName) - => new(keyName, s_parseBool, s_getBoolEditorConfigStringForValue); - - public static EditorConfigStorageLocation ForInt32Option(string keyName) - => new(keyName, s_parseInt32, s_getInt32EditorConfigStringForValue); - - public static EditorConfigStorageLocation ForStringOption(string keyName, string emptyStringRepresentation) - => new(keyName, s_parseString, (string value) => string.IsNullOrEmpty(value) ? emptyStringRepresentation : s_getStringEditorConfigStringForValue(value)); - - public static EditorConfigStorageLocation> ForBoolCodeStyleOption(string keyName, CodeStyleOption2 defaultValue) - => new(keyName, str => ParseBoolCodeStyleOption(str, defaultValue), value => GetBoolCodeStyleOptionEditorConfigStringForValue(value, defaultValue)); - - public static EditorConfigStorageLocation> ForStringCodeStyleOption(string keyName, CodeStyleOption2 defaultValue) - => new(keyName, str => ParseStringCodeStyleOption(str, defaultValue), value => GetStringCodeStyleOptionEditorConfigStringForValue(value, defaultValue)); - - private static readonly Func> s_parseBool = ParseBool; - private static Optional ParseBool(string str) - => bool.TryParse(str, out var result) ? result : new Optional(); - private static readonly Func s_getBoolEditorConfigStringForValue = GetBoolEditorConfigStringForValue; - private static string GetBoolEditorConfigStringForValue(bool value) => value.ToString().ToLowerInvariant(); - - private static readonly Func> s_parseInt32 = ParseInt32; - private static Optional ParseInt32(string str) - => int.TryParse(str, out var result) ? result : new Optional(); - - private static readonly Func> s_parseString = ParseString; - private static Optional ParseString(string str) - { - if (str.Equals("unset", StringComparison.Ordinal)) - { - return default; - } - - str ??= ""; - return str.Replace("\\r", "\r").Replace("\\n", "\n"); - } - - private static readonly Func s_getInt32EditorConfigStringForValue = GetInt32EditorConfigStringForValue; - private static string GetInt32EditorConfigStringForValue(int value) => value.ToString().ToLowerInvariant(); - - private static readonly Func s_getStringEditorConfigStringForValue = GetStringEditorConfigStringForValue; - private static string GetStringEditorConfigStringForValue(string value) => value.ToString().Replace("\r", "\\r").Replace("\n", "\\n"); - - private static Optional> ParseBoolCodeStyleOption(string str, CodeStyleOption2 defaultValue) - => CodeStyleHelpers.TryParseBoolEditorConfigCodeStyleOption(str, defaultValue, out var result) ? result : new Optional>(); - private static string GetBoolCodeStyleOptionEditorConfigStringForValue(CodeStyleOption2 value, CodeStyleOption2 defaultValue) - => $"{(value.Value ? "true" : "false")}{CodeStyleHelpers.GetEditorConfigStringNotificationPart(value, defaultValue)}"; - - private static Optional> ParseStringCodeStyleOption(string str, CodeStyleOption2 defaultValue) - => CodeStyleHelpers.TryParseStringEditorConfigCodeStyleOption(str, defaultValue, out var result) ? result : new Optional>(); - private static string GetStringCodeStyleOptionEditorConfigStringForValue(CodeStyleOption2 value, CodeStyleOption2 defaultValue) - => $"{value.Value.ToLowerInvariant()}{CodeStyleHelpers.GetEditorConfigStringNotificationPart(value, defaultValue)}"; - } -} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/EditorConfig/EditorConfigStorageLocation`1.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/EditorConfig/EditorConfigStorageLocation`1.cs deleted file mode 100644 index 6ad8d4d8895d0..0000000000000 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/EditorConfig/EditorConfigStorageLocation`1.cs +++ /dev/null @@ -1,110 +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 Microsoft.CodeAnalysis.CodeStyle; -using Microsoft.CodeAnalysis.Diagnostics; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.Options -{ - /// - /// Specifies that an option should be read from an .editorconfig file. - /// - internal sealed class EditorConfigStorageLocation : OptionStorageLocation2, IEditorConfigStorageLocation2 - { - public string KeyName { get; } - - private readonly Func> _parseValue; - private readonly Func _serializeValue; - -#if !CODE_STYLE - private readonly Func? _getValueFromOptionSet; - - public EditorConfigStorageLocation( - string keyName, - Func> parseValue, - Func serializeValue, - Func? getValueFromOptionSet) - : this(keyName, parseValue, serializeValue) - { - _getValueFromOptionSet = getValueFromOptionSet; - } -#endif - public EditorConfigStorageLocation( - string keyName, - Func> parseValue, - Func serializeValue) - { - KeyName = keyName; - _parseValue = parseValue; - _serializeValue = serializeValue; - } - - public bool TryGetOption(StructuredAnalyzerConfigOptions options, Type type, out object? result) - { - if (options.TryGetValue(KeyName, out var value)) - { - var ret = TryGetOption(value, out var typedResult); - result = typedResult; - return ret; - } - - result = null; - return false; - } - - internal bool TryGetOption(string value, [MaybeNullWhen(false)] out T result) - { - var optionalValue = _parseValue(value); - if (optionalValue.HasValue) - { - result = optionalValue.Value; - return result != null; - } - else - { - result = default!; - return false; - } - } - - public string GetEditorConfigStringValue(T value) - { - var editorConfigStringForValue = _serializeValue(value); - Contract.ThrowIfTrue(RoslynString.IsNullOrEmpty(editorConfigStringForValue)); - return editorConfigStringForValue; - } - - string IEditorConfigStorageLocation2.GetEditorConfigStringValue(object? value) - { - T typedValue; - if (value is ICodeStyleOption codeStyleOption) - { - typedValue = (T)codeStyleOption.AsCodeStyleOption(); - } - else - { - typedValue = (T)value!; - } - - return GetEditorConfigStringValue(typedValue); - } - -#if !CODE_STYLE - public string GetEditorConfigStringValue(OptionKey optionKey, OptionSet optionSet) - { - if (_getValueFromOptionSet != null) - { - var editorConfigStringForValue = _serializeValue(_getValueFromOptionSet(optionSet)); - Contract.ThrowIfTrue(RoslynString.IsNullOrEmpty(editorConfigStringForValue)); - return editorConfigStringForValue; - } - - return GetEditorConfigStringValue(optionSet.GetOption(optionKey)); - } -#endif - } -} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/EditorConfig/IEditorConfigStorageLocation.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/EditorConfig/IEditorConfigStorageLocation.cs deleted file mode 100644 index 9d6d0521f2b27..0000000000000 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/EditorConfig/IEditorConfigStorageLocation.cs +++ /dev/null @@ -1,18 +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.Diagnostics.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; - -namespace Microsoft.CodeAnalysis.Options -{ - internal interface IEditorConfigStorageLocation - { - bool TryGetOption(StructuredAnalyzerConfigOptions options, Type type, out object? value); - } -} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/EditorConfig/IEditorConfigStorageLocation2.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/EditorConfig/IEditorConfigStorageLocation2.cs deleted file mode 100644 index d12a62f7f52b8..0000000000000 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/EditorConfig/IEditorConfigStorageLocation2.cs +++ /dev/null @@ -1,47 +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. - -namespace Microsoft.CodeAnalysis.Options; - -internal interface IEditorConfigStorageLocation2 : IEditorConfigStorageLocation -{ - /// - /// The name of the editorconfig key for the option. - /// - string KeyName { get; } - - /// - /// Gets the editorconfig string representation for the specified . - /// - string GetEditorConfigStringValue(object? value); - -#if !CODE_STYLE - /// - /// Gets the editorconfig string representation for the option value stored in . - /// May combine values of multiple options stored in the set. - /// - string GetEditorConfigStringValue(OptionKey optionKey, OptionSet optionSet); -#endif -} - -internal static partial class Extensions -{ - /// - /// Gets the editorconfig string representation for this storage location. The result is a complete line of the - /// .editorconfig file, such as the following: - /// - /// dotnet_sort_system_directives_first = true - /// - /// - public static string GetEditorConfigString(this IEditorConfigStorageLocation2 location, object? value) - => GetEditorConfigStringImpl(location, location.GetEditorConfigStringValue(value)); - -#if !CODE_STYLE - public static string GetEditorConfigString(this IEditorConfigStorageLocation2 location, OptionKey optionKey, OptionSet optionSet) - => GetEditorConfigStringImpl(location, location.GetEditorConfigStringValue(optionKey, optionSet)); -#endif - - private static string GetEditorConfigStringImpl(IEditorConfigStorageLocation2 location, string serializedValue) - => $"{location.KeyName} = {serializedValue}"; -} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/EditorConfig/NamingStylePreferenceEditorConfigStorageLocation.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/EditorConfig/NamingStylePreferenceEditorConfigStorageLocation.cs deleted file mode 100644 index 650356dd5b95d..0000000000000 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/EditorConfig/NamingStylePreferenceEditorConfigStorageLocation.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections.Generic; -using System.Linq; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.Options -{ - internal sealed class NamingStylePreferenceEditorConfigStorageLocation : OptionStorageLocation2, IEditorConfigStorageLocation - { - public bool TryGetOption(StructuredAnalyzerConfigOptions options, Type type, out object result) - { - if (type == typeof(NamingStylePreferences)) - { - var preferences = options.GetNamingStylePreferences(); - result = preferences; - return !preferences.IsEmpty; - } - - throw ExceptionUtilities.UnexpectedValue(type); - } - } -} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/EditorConfigValueSerializer.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/EditorConfigValueSerializer.cs new file mode 100644 index 0000000000000..08522ee128e12 --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/EditorConfigValueSerializer.cs @@ -0,0 +1,71 @@ +// 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 Microsoft.CodeAnalysis.CodeStyle; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Options +{ + internal static class EditorConfigValueSerializer + { + private static string EscapeLineBreaks(string str) + => str.Replace("\\r", "\r").Replace("\\n", "\n"); + + private static string UnescapeLineBreaks(string str) + => str.Replace("\r", "\\r").Replace("\n", "\\n"); + + private static readonly EditorConfigValueSerializer s_bool = new( + parseValue: str => bool.TryParse(str, out var result) ? result : new Optional(), + serializeValue: value => value ? "true" : "false"); + + private static readonly EditorConfigValueSerializer s_int32 = new( + parseValue: str => int.TryParse(str, out var result) ? result : new Optional(), + serializeValue: StringExtensions.GetNumeral); + + private static readonly EditorConfigValueSerializer s_string = new( + parseValue: str => EscapeLineBreaks(str), + serializeValue: UnescapeLineBreaks); + + public static EditorConfigValueSerializer Default() + { + if (typeof(T) == typeof(bool)) + return (EditorConfigValueSerializer)(object)s_bool; + + if (typeof(T) == typeof(int)) + return (EditorConfigValueSerializer)(object)s_int32; + + if (typeof(T) == typeof(string)) + return (EditorConfigValueSerializer)(object)s_string; + + // TODO: https://github.com/dotnet/roslyn/issues/65787 + // Once all global options define a serializer this should be changed to: + // throw ExceptionUtilities.UnexpectedValue(typeof(T)); + return EditorConfigValueSerializer.Unsupported; + } + + public static EditorConfigValueSerializer String(string emptyStringRepresentation) + => new(parseValue: str => str.Equals(emptyStringRepresentation, StringComparison.Ordinal) ? default(Optional) : EscapeLineBreaks(str), + serializeValue: value => string.IsNullOrEmpty(value) ? emptyStringRepresentation : UnescapeLineBreaks(value)); + + public static EditorConfigValueSerializer> CodeStyle(CodeStyleOption2 defaultValue) + { + if (typeof(T) == typeof(bool)) + return (EditorConfigValueSerializer>)(object)CodeStyle((CodeStyleOption2)(object)defaultValue); + + if (typeof(T) == typeof(string)) + return (EditorConfigValueSerializer>)(object)CodeStyle((CodeStyleOption2)(object)defaultValue); + + throw ExceptionUtilities.UnexpectedValue(typeof(T)); + } + + public static EditorConfigValueSerializer> CodeStyle(CodeStyleOption2 defaultValue) + => new(parseValue: str => CodeStyleHelpers.TryParseBoolEditorConfigCodeStyleOption(str, defaultValue, out var result) ? result : new Optional>(), + serializeValue: value => (value.Value ? "true" : "false") + CodeStyleHelpers.GetEditorConfigStringNotificationPart(value, defaultValue)); + + public static EditorConfigValueSerializer> CodeStyle(CodeStyleOption2 defaultValue) + => new(parseValue: str => CodeStyleHelpers.TryParseStringEditorConfigCodeStyleOption(str, defaultValue, out var result) ? result : new Optional>(), + serializeValue: value => value.Value.ToLowerInvariant() + CodeStyleHelpers.GetEditorConfigStringNotificationPart(value, defaultValue)); + } +} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/EditorConfigValueSerializer`1.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/EditorConfigValueSerializer`1.cs new file mode 100644 index 0000000000000..fac2f7394b857 --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/EditorConfigValueSerializer`1.cs @@ -0,0 +1,69 @@ +// 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 Microsoft.CodeAnalysis.CodeStyle; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Options +{ + /// + /// Specifies that an option should be read from an .editorconfig file. + /// + internal sealed class EditorConfigValueSerializer : IEditorConfigValueSerializer + { + public static readonly EditorConfigValueSerializer Unsupported = new( + parseValue: _ => throw new NotSupportedException("Option does not support serialization to editorconfig format"), + serializeValue: _ => throw new NotSupportedException("Option does not support serialization to editorconfig format")); + + private readonly Func> _parseValue; + private readonly Func _serializeValue; + + public EditorConfigValueSerializer( + Func> parseValue, + Func serializeValue) + { + _parseValue = parseValue; + _serializeValue = serializeValue; + } + + bool IEditorConfigValueSerializer.TryParse(string value, out object? result) + { + if (TryParseValue(value, out var typedResult)) + { + result = typedResult; + return true; + } + + result = null; + return false; + } + + internal bool TryParseValue(string value, [MaybeNullWhen(false)] out T result) + { + var optionalValue = _parseValue(value); + if (optionalValue.HasValue) + { + result = optionalValue.Value; + return result != null; + } + else + { + result = default!; + return false; + } + } + + public string GetEditorConfigStringValue(T value) + { + var editorConfigStringForValue = _serializeValue(value); + Contract.ThrowIfTrue(RoslynString.IsNullOrEmpty(editorConfigStringForValue)); + return editorConfigStringForValue; + } + + string IEditorConfigValueSerializer.Serialize(object? value) + => GetEditorConfigStringValue((T)value!); + } +} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/IOptionWithGroup.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/IEditorConfigValueSerializer.cs similarity index 53% rename from src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/IOptionWithGroup.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/IEditorConfigValueSerializer.cs index fc8dec60201a2..94329c762f830 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/IOptionWithGroup.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/IEditorConfigValueSerializer.cs @@ -2,16 +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. +using System; + namespace Microsoft.CodeAnalysis.Options { - /// - /// Group/sub-feature associated with an . - /// - internal interface IOptionWithGroup : IOption2 + internal interface IEditorConfigValueSerializer { + bool TryParse(string value, out object? result); + /// - /// Group/sub-feature for this option. + /// Gets the editorconfig string representation for the specified . /// - OptionGroup Group { get; } + string Serialize(object? value); } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/IOption2.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/IOption2.cs index fa5ed25959ef3..8ce94a74e8fc7 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/IOption2.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/IOption2.cs @@ -4,10 +4,6 @@ using System; -#if CODE_STYLE -using System.Collections.Immutable; -#endif - namespace Microsoft.CodeAnalysis.Options { /// @@ -22,16 +18,11 @@ internal interface IOption2 : IEquatable , IOption #endif { - OptionDefinition OptionDefinition { get; } + OptionDefinition Definition { get; } + IPublicOption? PublicOption { get; } #if CODE_STYLE - string Feature { get; } - string Name { get; } - Type Type { get; } - object? DefaultValue { get; } bool IsPerLanguage { get; } - - ImmutableArray StorageLocations { get; } #endif } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/IOptionReader.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/IOptionReader.cs new file mode 100644 index 0000000000000..1d3a60418f6c8 --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/IOptionReader.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.Collections.Generic; +using System.Diagnostics; +using System.Text; +using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace Microsoft.CodeAnalysis.Options; + +internal interface IOptionsReader +{ + bool TryGetOption(OptionKey2 optionKey, out T value); +} + +internal sealed class AnalyzerConfigOptionsReader : IOptionsReader +{ + public readonly AnalyzerConfigOptions Options; + + public AnalyzerConfigOptionsReader(AnalyzerConfigOptions options) + { + Options = options; + } + + public bool TryGetOption(OptionKey2 optionKey, out T value) + => Options.TryGetEditorConfigOption(optionKey.Option, out value); +} + +internal static partial class Extensions +{ + public static IOptionsReader GetOptionsReader(this AnalyzerConfigOptions configOptions) + => configOptions as IOptionsReader ?? new AnalyzerConfigOptionsReader(configOptions); + + public static T GetOption(this IOptionsReader options, Option2 option) + => options.TryGetOption(new OptionKey2(option), out var value) ? value! : option.DefaultValue; + + public static T GetOption(this IOptionsReader options, Option2 option, T defaultValue) + => options.TryGetOption(new OptionKey2(option), out var value) ? value! : defaultValue; + + public static T GetOption(this IOptionsReader options, PerLanguageOption2 option, string language) + => options.TryGetOption(new OptionKey2(option, language), out var value) ? value! : option.DefaultValue; + + public static T GetOption(this IOptionsReader options, PerLanguageOption2 option, string language, T defaultValue) + => options.TryGetOption(new OptionKey2(option, language), out var value) ? value! : defaultValue; + + public static T GetOptionValue(this IOptionsReader options, Option2> option, T defaultValue) + => options.TryGetOption>(new OptionKey2(option), out var style) ? style!.Value : defaultValue; + + public static T GetOptionValue(this IOptionsReader options, PerLanguageOption2> option, string language, T defaultValue) + => options.TryGetOption>(new OptionKey2(option, language), out var style) ? style!.Value : defaultValue; +} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/IPublicOption.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/IPublicOption.cs new file mode 100644 index 0000000000000..e17229edcbbdf --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/IPublicOption.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. + +#pragma warning disable RS0030 // Do not used banned APIs + +namespace Microsoft.CodeAnalysis.Options; + +/// +/// Interface implemented by public options (Option and PerLanguageOption) +/// to distinguish them from internal ones ( and ). +/// +internal interface IPublicOption : IOption2 +{ +} + diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/InternalOptionStorageMapping.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/InternalOptionStorageMapping.cs new file mode 100644 index 0000000000000..7435c45e6929c --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/InternalOptionStorageMapping.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. + +namespace Microsoft.CodeAnalysis.Options; + +/// +/// Some options store their values in a type that's not accessible publicly. +/// The mapping provides translation between the two representations. +/// +internal abstract class OptionStorageMapping +{ + /// + /// The option that stores the value internally. + /// + public IOption2 InternalOption { get; } + + public OptionStorageMapping(IOption2 internalOption) + => InternalOption = internalOption; + + /// + /// Converts inernal option value representation to public. + /// + public abstract object? ToPublicOptionValue(object? internalValue); + + /// + /// Returns a new internal value created by updating to . + /// + public abstract object? UpdateInternalOptionValue(object? currentInternalValue, object? newPublicValue); +} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/LocalClientSettingsStorageLocation.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/LocalClientSettingsStorageLocation.cs deleted file mode 100644 index d4cf826b9c501..0000000000000 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/LocalClientSettingsStorageLocation.cs +++ /dev/null @@ -1,35 +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; - -namespace Microsoft.CodeAnalysis.Options; - -/// -/// Specifies that the option should be stored into local client settings storage. -/// -/// -/// Unlike LocalUserRegistryOptionPersister, which accesses the registry directly this storage is managed by VS Settings component. -/// -/// TODO (https://github.com/dotnet/roslyn/issues/62683): The options that use this storage are global client options. This storage should really be in the VS layer but currently -/// option storage is coupled with option definition and thus the storage is needed here. -/// -internal sealed class LocalClientSettingsStorageLocation : ClientSettingsStorageLocation -{ - public override bool IsMachineLocal => true; - - public LocalClientSettingsStorageLocation(string keyName) - : base(keyName) - { - } - - /// - /// Creates a that has different key names for different languages. - /// - /// A function that maps from a value to the key name. - public LocalClientSettingsStorageLocation(Func keyNameFromLanguageName) - : base(keyNameFromLanguageName) - { - } -} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/LocalUserProfileStorageLocation.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/LocalUserProfileStorageLocation.cs deleted file mode 100644 index 6c648abed60c4..0000000000000 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/LocalUserProfileStorageLocation.cs +++ /dev/null @@ -1,17 +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. - -namespace Microsoft.CodeAnalysis.Options -{ - /// - /// Specifies that the option should be stored into the user's local Roslyn specific registry hive. - /// - internal sealed class LocalUserProfileStorageLocation : OptionStorageLocation2 - { - public string KeyName { get; } - - public LocalUserProfileStorageLocation(string keyName) - => KeyName = keyName; - } -} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/Option2.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/Option2.cs new file mode 100644 index 0000000000000..af091e4e2b2b0 --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/Option2.cs @@ -0,0 +1,109 @@ +// 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.Diagnostics; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Options +{ + /// + /// Marker interface for options that has the same value for all languages. + /// + internal interface ISingleValuedOption : IOption2 + { + /// + /// The language name that supports this option, or null if it's supported by multiple languages. + /// + /// + /// This is an optional metadata used for: + /// + /// Analyzer id to option mapping, used (for example) by configure code-style code action + /// EditorConfig UI to determine whether to put this option under [*.cs], [*.vb], or [*.{cs,vb}] + /// + /// Note that this property is not (and should not be) used for computing option values or storing options. + /// + public string? LanguageName { get; } + } + + /// + internal interface ISingleValuedOption : ISingleValuedOption + { + } + + internal partial class Option2 : ISingleValuedOption + { + public OptionDefinition Definition { get; } + public IPublicOption? PublicOption { get; } + public string? LanguageName { get; } + + internal Option2(OptionDefinition definition, string? languageName, Func? publicOptionFactory) + { + Definition = definition; + LanguageName = languageName; + PublicOption = publicOptionFactory?.Invoke(this); + } + + public Option2( + string name, + T defaultValue, + OptionGroup? group = null, + string? languageName = null, + bool isEditorConfigOption = false, + EditorConfigValueSerializer? serializer = null) + : this(new OptionDefinition(defaultValue, serializer, group, name, storageMapping: null, isEditorConfigOption), languageName, publicOptionFactory: null) + { + VerifyNamingConvention(); + } + + [Conditional("DEBUG")] + private void VerifyNamingConvention() + { + // TODO: remove, once all options have editorconfig-like name https://github.com/dotnet/roslyn/issues/65787 + if (!Definition.IsEditorConfigOption) + { + return; + } + + Debug.Assert(LanguageName is null == (Definition.ConfigName.StartsWith("dotnet_", StringComparison.Ordinal) || + Definition.ConfigName is "file_header_template" or "insert_final_newline")); + Debug.Assert(LanguageName is LanguageNames.CSharp == Definition.ConfigName.StartsWith(OptionDefinition.CSharpConfigNamePrefix, StringComparison.Ordinal)); + Debug.Assert(LanguageName is LanguageNames.VisualBasic == Definition.ConfigName.StartsWith(OptionDefinition.VisualBasicConfigNamePrefix, StringComparison.Ordinal)); + } + + public T DefaultValue => Definition.DefaultValue; + OptionDefinition IOption2.Definition => Definition; + +#if CODE_STYLE + bool IOption2.IsPerLanguage => false; +#else + string IOption.Feature => "config"; + string IOption.Name => Definition.ConfigName; + object? IOption.DefaultValue => Definition.DefaultValue; + bool IOption.IsPerLanguage => false; + Type IOption.Type => Definition.Type; + ImmutableArray IOption.StorageLocations => ImmutableArray.Empty; +#endif + + public override string ToString() => Definition.ToString(); + + public override int GetHashCode() => Definition.GetHashCode(); + + public override bool Equals(object? obj) => Equals(obj as IOption2); + + public bool Equals(IOption2? other) + { + if (ReferenceEquals(this, other)) + { + return true; + } + + return Definition == other?.Definition; + } + + public static implicit operator OptionKey2(Option2 option) + => new(option); + } +} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/Option2`1.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/Option2`1.cs deleted file mode 100644 index 2abae256bd5d6..0000000000000 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/Option2`1.cs +++ /dev/null @@ -1,126 +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; - -namespace Microsoft.CodeAnalysis.Options -{ - /// - /// Marker interface for options that has the same value for all languages. - /// - internal interface ISingleValuedOption : IOptionWithGroup - { - /// - /// The language name that supports this option, or null if it's supported by multiple languages. - /// - /// - /// This is an optional metadata used for: - /// - /// Analyzer id to option mapping, used (for example) by configure code-style code action - /// EditorConfig UI to determine whether to put this option under [*.cs], [*.vb], or [*.{cs,vb}] - /// - /// Note that this property is not (and should not be) used for computing option values or storing options. - /// - public string? LanguageName { get; } - } - - /// - internal interface ISingleValuedOption : ISingleValuedOption - { - } - - /// - /// An global option. An instance of this class can be used to access an option value from an OptionSet. - /// - internal partial class Option2 : ISingleValuedOption - { - public OptionDefinition OptionDefinition { get; } - - /// - public string Feature => OptionDefinition.Feature; - - /// - internal OptionGroup Group => OptionDefinition.Group; - - /// - public string Name => OptionDefinition.Name; - - /// - public T DefaultValue => (T)OptionDefinition.DefaultValue!; - - /// - public Type Type => OptionDefinition.Type; - - /// - /// Storage locations for the option. - /// - public ImmutableArray StorageLocations { get; } - - public Option2(string? feature, string? name, T defaultValue) - : this(feature, group: OptionGroup.Default, name, defaultValue, storageLocations: ImmutableArray.Empty) - { - } - - public Option2(string? feature, string? name, T defaultValue, OptionStorageLocation2 storageLocation) - : this(feature, group: OptionGroup.Default, name, defaultValue, ImmutableArray.Create(storageLocation)) - { - } - - public Option2(string? feature, OptionGroup group, string? name, T defaultValue, OptionStorageLocation2 storageLocation) - : this(feature, group, name, defaultValue, ImmutableArray.Create(storageLocation)) - { - } - - public Option2(string? feature, OptionGroup group, string? name, T defaultValue, ImmutableArray storageLocations) - : this(feature, group, name, defaultValue, storageLocations, null) - { - } - - public Option2(string? feature, OptionGroup group, string? name, T defaultValue, ImmutableArray storageLocations, string? languageName) - { - OptionDefinition = new OptionDefinition(feature, group, name, storageLocations.GetOptionConfigName(feature, name), defaultValue, typeof(T)); - this.StorageLocations = storageLocations; - LanguageName = languageName; - } - -#if CODE_STYLE - object? IOption2.DefaultValue => this.DefaultValue; - - bool IOption2.IsPerLanguage => false; -#else - object? IOption.DefaultValue => this.DefaultValue; - - bool IOption.IsPerLanguage => false; - - ImmutableArray IOption.StorageLocations - => this.StorageLocations.As(); -#endif - - OptionGroup IOptionWithGroup.Group => this.Group; - - OptionDefinition IOption2.OptionDefinition => OptionDefinition; - - public string? LanguageName { get; } - - public override string ToString() => OptionDefinition.ToString(); - - public override int GetHashCode() => OptionDefinition.GetHashCode(); - - public override bool Equals(object? obj) => Equals(obj as IOption2); - - public bool Equals(IOption2? other) - { - if (ReferenceEquals(this, other)) - { - return true; - } - - return OptionDefinition == other?.OptionDefinition; - } - - public static implicit operator OptionKey2(Option2 option) - => new(option); - } -} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/OptionDefinition.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/OptionDefinition.cs index de608c2d00a2b..37c6408db1ae6 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/OptionDefinition.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/OptionDefinition.cs @@ -3,22 +3,17 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Generic; using Microsoft.CodeAnalysis.CodeStyle; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Options { - [NonDefaultable] - internal readonly struct OptionDefinition : IEquatable + internal abstract class OptionDefinition : IEquatable { - private const string FeatureConfig = "config"; - - private readonly string? _name; - - /// - /// Feature this option is associated with. Obsolete. - /// - public string Feature { get; } + // Editorconfig name prefixes used for C#/VB specific options: + public const string CSharpConfigNamePrefix = "csharp_"; + public const string VisualBasicConfigNamePrefix = "visual_basic_"; /// /// Optional group/sub-feature for this option. @@ -31,35 +26,43 @@ namespace Microsoft.CodeAnalysis.Options public string ConfigName { get; } /// - /// The default value of the option. + /// True if the value of the option may be stored in an editorconfig file. /// - public object? DefaultValue { get; } + public bool IsEditorConfigOption { get; } /// - /// The type of the option value. + /// Mapping between the public option storage and internal option storage. /// - public Type Type { get; } + public OptionStorageMapping? StorageMapping { get; } + + /// + /// The untyped/boxed default value of the option. + /// + public object? DefaultValue { get; } - public OptionDefinition(string? feature, OptionGroup group, string? name, string configName, object? defaultValue, Type type) + public OptionDefinition(OptionGroup? group, string configName, object? defaultValue, OptionStorageMapping? storageMapping, bool isEditorConfigOption) { ConfigName = configName; - Feature = feature ?? FeatureConfig; - _name = name; - Group = group; + Group = group ?? OptionGroup.Default; + StorageMapping = storageMapping; + IsEditorConfigOption = isEditorConfigOption; DefaultValue = defaultValue; - Type = type; } /// - /// The legacy name of the option. + /// The type of the option value. /// - public string Name => _name ?? ConfigName; + public abstract Type Type { get; } + + public IEditorConfigValueSerializer Serializer => SerializerImpl; + + protected abstract IEditorConfigValueSerializer SerializerImpl { get; } - public override bool Equals(object? obj) - => obj is OptionDefinition key && Equals(key); + public override bool Equals(object? other) + => Equals(other as OptionDefinition); - public bool Equals(OptionDefinition other) - => ConfigName == other.ConfigName; + public bool Equals(OptionDefinition? other) + => ConfigName == other?.ConfigName; public override int GetHashCode() => ConfigName.GetHashCode(); @@ -67,37 +70,35 @@ public override int GetHashCode() public override string ToString() => ConfigName; - public static bool operator ==(OptionDefinition left, OptionDefinition right) - => left.Equals(right); - - public static bool operator !=(OptionDefinition left, OptionDefinition right) - => !left.Equals(right); - - #region Backward compat helpers + public static bool operator ==(OptionDefinition? left, OptionDefinition? right) + => ReferenceEquals(left, right) || left?.Equals(right) == true; - // The following are used only to implement equality/ToString of public Option and PerLanguageOption options. - // Public options can be instantiated with non-unique config name and thus we need to include default value in the equality - // to avoid collisions among them. - - public string PublicOptionDefinitionToString() - => $"{Feature} - {_name}"; + public static bool operator !=(OptionDefinition? left, OptionDefinition? right) + => !(left == right); + } - public bool PublicOptionDefinitionEquals(OptionDefinition other) + internal sealed class OptionDefinition : OptionDefinition + { + public new T DefaultValue { get; } + public new EditorConfigValueSerializer Serializer { get; } + + public OptionDefinition( + T defaultValue, + EditorConfigValueSerializer? serializer, + OptionGroup? group, + string configName, + OptionStorageMapping? storageMapping, + bool isEditorConfigOption) + : base(group, configName, defaultValue, storageMapping, isEditorConfigOption) { - var equals = this.Name == other.Name && - this.Feature == other.Feature && - this.Group == other.Group; - - // DefaultValue and Type can differ between different but equivalent implementations of "ICodeStyleOption". - // So, we skip these fields for equality checks of code style options. - if (equals && !(this.DefaultValue is ICodeStyleOption)) - { - equals = Equals(this.DefaultValue, other.DefaultValue) && this.Type == other.Type; - } - - return equals; + DefaultValue = defaultValue; + Serializer = serializer ?? EditorConfigValueSerializer.Default(); } - #endregion + public override Type Type + => typeof(T); + + protected override IEditorConfigValueSerializer SerializerImpl + => Serializer; } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/OptionGroup.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/OptionGroup.cs index 5efac0a1b9d3d..25d3df8b152fb 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/OptionGroup.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/OptionGroup.cs @@ -13,12 +13,18 @@ internal sealed class OptionGroup { public static readonly OptionGroup Default = new(string.Empty, int.MaxValue); - public OptionGroup(string description, int priority) + public OptionGroup(string description, int priority, OptionGroup? parent = null) { - Description = description ?? throw new ArgumentNullException(nameof(description)); + Description = description; Priority = priority; + Parent = parent; } + /// + /// Optional parent group. + /// + public OptionGroup? Parent { get; } + /// /// A localizable resource description string for the option group. /// diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/OptionKey2.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/OptionKey2.cs index dcdf27dbff5df..3cc718626a0cc 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/OptionKey2.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/OptionKey2.cs @@ -18,6 +18,14 @@ namespace Microsoft.CodeAnalysis.Options public IOption2 Option { get; } public string? Language { get; } + public OptionKey2(IOption2 option, string? language) + { + Debug.Assert(option.IsPerLanguage == language is not null); + + Option = option; + Language = language; + } + public OptionKey2(IPerLanguageValuedOption option, string language) { Debug.Assert(option.IsPerLanguage); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/OptionStorageLocation2.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/OptionStorageLocation2.cs deleted file mode 100644 index 2aee10b089d76..0000000000000 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/OptionStorageLocation2.cs +++ /dev/null @@ -1,43 +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 System.Collections.Generic; -using System.Linq; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.Options -{ - /// - /// The base type of all types that specify where options are stored. - /// - internal abstract class OptionStorageLocation2 -#if !CODE_STYLE - : OptionStorageLocation -#endif - { - } - - internal static partial class Extensions - { - public static string GetOptionConfigName(this ImmutableArray locations, string? feature, string? name) - => GetOptionConfigName(locations.OfType(), feature, name); - -#if !CODE_STYLE - public static string GetOptionConfigName(this ImmutableArray locations, string? feature, string? name) - => GetOptionConfigName(locations.OfType(), feature, name); -#endif - - private static string GetOptionConfigName(IEnumerable locations, string? feature, string? name) - { - // If this option is an editorconfig option we use the editorconfig name specified in the storage location. - // Otherwise, the option is a global option. If it is a global option with a new unique name then feature is unspecified and we use the name as is. - // Otherwise, the option is a global option with an old name and we join feature and name to form a unique config name for now. We expect these options get eventually renamed. - // TODO: https://github.com/dotnet/roslyn/issues/65787 - var configName = locations.SingleOrDefault()?.KeyName ?? (feature is null ? name : feature + "_" + name); - Contract.ThrowIfNull(configName); - return configName; - } - } -} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/PerLanguageOption2.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/PerLanguageOption2.cs index 23182fb4a383b..0c84611f6ac56 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/PerLanguageOption2.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/PerLanguageOption2.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Diagnostics; using System.Collections.Immutable; namespace Microsoft.CodeAnalysis.Options @@ -11,7 +12,7 @@ namespace Microsoft.CodeAnalysis.Options /// Marker interface for . /// This option may apply to multiple languages, such that the option can have a different value for each language. /// - internal interface IPerLanguageValuedOption : IOptionWithGroup + internal interface IPerLanguageValuedOption : IOption2 { } @@ -26,103 +27,56 @@ internal interface IPerLanguageValuedOption : IPerLanguageValuedOption /// internal partial class PerLanguageOption2 : IPerLanguageValuedOption { - public OptionDefinition OptionDefinition { get; } + public OptionDefinition Definition { get; } + public IPublicOption? PublicOption { get; } - /// - public string Feature => OptionDefinition.Feature; - - /// - internal OptionGroup Group => OptionDefinition.Group; - - /// - public string Name => OptionDefinition.Name; - - /// - public Type Type => OptionDefinition.Type; - - /// - public T DefaultValue => (T)OptionDefinition.DefaultValue!; - - /// - /// Storage locations for the option. - /// - public ImmutableArray StorageLocations { get; } - - public PerLanguageOption2(string? feature, string? name, T defaultValue) - : this(feature, name, defaultValue, storageLocations: ImmutableArray.Empty) - { - } - - public PerLanguageOption2( - string? feature, string? name, T defaultValue, - OptionStorageLocation2 storageLocation) - : this(feature, group: OptionGroup.Default, name, defaultValue, ImmutableArray.Create(storageLocation)) - { - } - - public PerLanguageOption2( - string? feature, string? name, T defaultValue, - OptionStorageLocation2 storageLocation1, - OptionStorageLocation2 storageLocation2, - OptionStorageLocation2 storageLocation3) - : this(feature, group: OptionGroup.Default, name, defaultValue, - ImmutableArray.Create(storageLocation1, storageLocation2, storageLocation3)) + internal PerLanguageOption2(OptionDefinition optionDefinition, Func? publicOptionFactory) { + Definition = optionDefinition; + PublicOption = publicOptionFactory?.Invoke(this); } public PerLanguageOption2( - string? feature, string? name, T defaultValue, - ImmutableArray storageLocations) - : this(feature, group: OptionGroup.Default, name, defaultValue, storageLocations) + string name, + T defaultValue, + OptionGroup? group = null, + bool isEditorConfigOption = false, + EditorConfigValueSerializer? serializer = null) + : this(new OptionDefinition(defaultValue, serializer, group, name, storageMapping: null, isEditorConfigOption), publicOptionFactory: null) { + VerifyNamingConvention(); } - public PerLanguageOption2(string? feature, OptionGroup group, string? name, T defaultValue) - : this(feature, group, name, defaultValue, ImmutableArray.Empty) + [Conditional("DEBUG")] + private void VerifyNamingConvention() { - } - - public PerLanguageOption2( - string? feature, OptionGroup group, string? name, T defaultValue, - OptionStorageLocation2 storageLocation) - : this(feature, group, name, defaultValue, ImmutableArray.Create(storageLocation)) - { - } - - public PerLanguageOption2( - string? feature, OptionGroup group, string? name, T defaultValue, - OptionStorageLocation2 storageLocation1, OptionStorageLocation2 storageLocation2) - : this(feature, group, name, defaultValue, ImmutableArray.Create(storageLocation1, storageLocation2)) - { - } + // TODO: remove, once all options have editorconfig-like name https://github.com/dotnet/roslyn/issues/65787 + if (!Definition.IsEditorConfigOption) + { + return; + } - public PerLanguageOption2( - string? feature, OptionGroup group, string? name, T defaultValue, - ImmutableArray storageLocations) - { - OptionDefinition = new OptionDefinition(feature, group, name, storageLocations.GetOptionConfigName(feature, name), defaultValue, typeof(T)); - this.StorageLocations = storageLocations; + // options with per-language values shouldn't have language-specific prefix + Debug.Assert(!Definition.ConfigName.StartsWith(OptionDefinition.CSharpConfigNamePrefix, StringComparison.Ordinal)); + Debug.Assert(!Definition.ConfigName.StartsWith(OptionDefinition.VisualBasicConfigNamePrefix, StringComparison.Ordinal)); } - OptionGroup IOptionWithGroup.Group => this.Group; - - OptionDefinition IOption2.OptionDefinition => OptionDefinition; + OptionDefinition IOption2.Definition => Definition; + public T DefaultValue => Definition.DefaultValue; #if CODE_STYLE - object? IOption2.DefaultValue => this.DefaultValue; - bool IOption2.IsPerLanguage => true; #else - object? IOption.DefaultValue => this.DefaultValue; - + string IOption.Feature => "config"; + string IOption.Name => Definition.ConfigName; + object? IOption.DefaultValue => Definition.DefaultValue; bool IOption.IsPerLanguage => true; - - ImmutableArray IOption.StorageLocations - => this.StorageLocations.As(); + Type IOption.Type => Definition.Type; + ImmutableArray IOption.StorageLocations => ImmutableArray.Empty; #endif - public override string ToString() => OptionDefinition.ToString(); + public override string ToString() => Definition.ToString(); - public override int GetHashCode() => OptionDefinition.GetHashCode(); + public override int GetHashCode() => Definition.GetHashCode(); public override bool Equals(object? obj) => Equals(obj as IOption2); @@ -133,7 +87,7 @@ public bool Equals(IOption2? other) return true; } - return OptionDefinition == other?.OptionDefinition; + return Definition == other?.Definition; } } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/PublicOptionFactory.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/PublicOptionFactory.cs new file mode 100644 index 0000000000000..170fdd0d2d5df --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/PublicOptionFactory.cs @@ -0,0 +1,146 @@ +// 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.CodeStyle; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Options; + +internal static class PublicOptionFactory +{ +#if CODE_STYLE +#pragma warning disable IDE0060 // Remove unused parameter + + // Stubs to avoid #ifdefs at call sites. + + public static Option2 WithPublicOption(this Option2 option, string feature, string name, Func toPublicValue, Func toInternalValue) + => option; + + public static PerLanguageOption2 WithPublicOption(this PerLanguageOption2 option, string feature, string name, Func toPublicValue, Func toInternalValue) + => option; + + public static Option2 WithPublicOption(this Option2 option, string feature, string name) + => option; + + public static Option2> WithPublicOption(this Option2> option, string feature, string name) + => option; + + public static PerLanguageOption2 WithPublicOption(this PerLanguageOption2 option, string feature, string name) + => option; + + public static PerLanguageOption2> WithPublicOption(this PerLanguageOption2> option, string feature, string name) + => option; + +#pragma warning restore +#else +#pragma warning disable RS0030 // Do not used banned APIs: Option, PerLanguageOption + private sealed class StorageMapping : OptionStorageMapping + { + private readonly Func _toPublicValue; + private readonly Func _toInternalValue; + + public StorageMapping(IOption2 internalOption, Func toPublicValue, Func toInternalValue) + : base(internalOption) + { + _toPublicValue = toPublicValue; + _toInternalValue = toInternalValue; + } + + public override object? ToPublicOptionValue(object? internalValue) + => _toPublicValue(internalValue); + + public override object? UpdateInternalOptionValue(object? currentInternalValue, object? newPublicValue) + => _toInternalValue(newPublicValue); + } + + private static OptionDefinition ToPublicOptionDefinition(this OptionDefinition definition, IOption2 internalOption, Func toPublicValue, Func toInternalValue) + => new( + toPublicValue(definition.DefaultValue), + serializer: EditorConfigValueSerializer.Unsupported, // public option instances do not need to be serialized to editorconfig + definition.Group, + definition.ConfigName, + new StorageMapping(internalOption, value => toPublicValue((T)value!), value => toInternalValue((TPublicValue)value!)), + definition.IsEditorConfigOption); + + public static Option2 WithPublicOption(this Option2 option, string feature, string name, Func toPublicValue, Func toInternalValue) + => new( + option.Definition, + option.LanguageName, + publicOptionFactory: internalOption => new Option( + option.Definition.ToPublicOptionDefinition(internalOption, toPublicValue, toInternalValue), + feature, + name, + ImmutableArray.Empty)); + + public static PerLanguageOption2 WithPublicOption(this PerLanguageOption2 option, string feature, string name, Func toPublicValue, Func toInternalValue) + => new( + option.Definition, + publicOptionFactory: internalOption => new PerLanguageOption( + option.Definition.ToPublicOptionDefinition(internalOption, toPublicValue, toInternalValue), + feature, + name, + ImmutableArray.Empty)); + + public static Option2 WithPublicOption(this Option2 option, string feature, string name) + => WithPublicOption(option, feature, name, static value => value, static value => value); + + public static Option2> WithPublicOption(this Option2> option, string feature, string name) + => WithPublicOption(option, feature, name, static value => new CodeStyleOption(value), static value => value.UnderlyingOption); + + public static PerLanguageOption2 WithPublicOption(this PerLanguageOption2 option, string feature, string name) + => WithPublicOption(option, feature, name, static value => value, static value => value); + + public static PerLanguageOption2> WithPublicOption(this PerLanguageOption2> option, string feature, string name) + => WithPublicOption(option, feature, name, static value => new CodeStyleOption(value), static value => value.UnderlyingOption); + + public static Option ToPublicOption(this Option2 option) + { + Contract.ThrowIfNull(option.PublicOption); + return (Option)option.PublicOption; + } + + public static PerLanguageOption ToPublicOption(this PerLanguageOption2 option) + { + Contract.ThrowIfNull(option.PublicOption); + return (PerLanguageOption)option.PublicOption; + } + + public static Option> ToPublicOption(this Option2> option) + { + Contract.ThrowIfNull(option.PublicOption); + return (Option>)option.PublicOption; + } + + public static PerLanguageOption> ToPublicOption(this PerLanguageOption2> option) + { + Contract.ThrowIfNull(option.PublicOption); + return (PerLanguageOption>)option.PublicOption; + } + + // The following are used only to implement equality/ToString of public Option and PerLanguageOption options. + // Public options can be instantiated with non-unique config name and thus we need to include default value in the equality + // to avoid collisions among them. + + public static string PublicOptionDefinitionToString(this IOption2 option) + => $"{option.Feature} - {option.Name}"; + + public static bool PublicOptionDefinitionEquals(this IOption2 x, IOption2 y) + { + var equals = x.Definition.ConfigName == y.Definition.ConfigName && x.Definition.Group == y.Definition.Group; + + // DefaultValue and Type can differ between different but equivalent implementations of "ICodeStyleOption". + // So, we skip these fields for equality checks of code style options. + if (equals && x.DefaultValue is not ICodeStyleOption) + { + equals = Equals(x.DefaultValue, y.DefaultValue) && x.Type == y.Type; + } + + return equals; + } + +#pragma warning restore +#endif +} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/RoamingProfileStorageLocation.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/RoamingProfileStorageLocation.cs deleted file mode 100644 index ec382f18d23df..0000000000000 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/RoamingProfileStorageLocation.cs +++ /dev/null @@ -1,29 +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; - -namespace Microsoft.CodeAnalysis.Options; - -/// -/// Specifies that the option should be stored into a roamed profile across machines. -/// -internal sealed class RoamingProfileStorageLocation : ClientSettingsStorageLocation -{ - public override bool IsMachineLocal => false; - - public RoamingProfileStorageLocation(string keyName) - : base(keyName) - { - } - - /// - /// Creates a that has different key names for different languages. - /// - /// A function that maps from a value to the key name. - public RoamingProfileStorageLocation(Func keyNameFromLanguageName) - : base(keyNameFromLanguageName) - { - } -} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/AbstractSimplification.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/AbstractSimplification.cs index 4b64c5e904665..77c93a2aef321 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/AbstractSimplification.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/AbstractSimplification.cs @@ -7,11 +7,12 @@ using System.Text; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.Simplification; internal abstract class AbstractSimplification : ISimplification { public abstract SimplifierOptions DefaultOptions { get; } - public abstract SimplifierOptions GetSimplifierOptions(AnalyzerConfigOptions options, SimplifierOptions? fallbackOptions); + public abstract SimplifierOptions GetSimplifierOptions(IOptionsReader options, SimplifierOptions? fallbackOptions); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/ISimplification.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/ISimplification.cs index a8a6ce9c97547..367ea4be74965 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/ISimplification.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/ISimplification.cs @@ -3,11 +3,12 @@ // See the LICENSE file in the project root for more information. using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.Simplification; internal interface ISimplification { SimplifierOptions DefaultOptions { get; } - SimplifierOptions GetSimplifierOptions(AnalyzerConfigOptions options, SimplifierOptions? fallbackOptions); + SimplifierOptions GetSimplifierOptions(IOptionsReader options, SimplifierOptions? fallbackOptions); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/SimplifierOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/SimplifierOptions.cs index 95f53c210a1a9..112b775321ba4 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/SimplifierOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/SimplifierOptions.cs @@ -8,12 +8,12 @@ using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Options; #if !CODE_STYLE using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.CodeGeneration; #endif @@ -75,22 +75,22 @@ internal interface SimplifierOptionsProvider internal static partial class SimplifierOptionsProviders { - internal static SimplifierOptions.CommonOptions GetCommonSimplifierOptions(this AnalyzerConfigOptions options, SimplifierOptions.CommonOptions? fallbackOptions) + internal static SimplifierOptions.CommonOptions GetCommonSimplifierOptions(this IOptionsReader options, string language, SimplifierOptions.CommonOptions? fallbackOptions) { fallbackOptions ??= SimplifierOptions.CommonOptions.Default; return new() { - QualifyFieldAccess = options.GetEditorConfigOption(CodeStyleOptions2.QualifyFieldAccess, fallbackOptions.QualifyFieldAccess), - QualifyPropertyAccess = options.GetEditorConfigOption(CodeStyleOptions2.QualifyPropertyAccess, fallbackOptions.QualifyPropertyAccess), - QualifyMethodAccess = options.GetEditorConfigOption(CodeStyleOptions2.QualifyMethodAccess, fallbackOptions.QualifyMethodAccess), - QualifyEventAccess = options.GetEditorConfigOption(CodeStyleOptions2.QualifyEventAccess, fallbackOptions.QualifyEventAccess), - PreferPredefinedTypeKeywordInMemberAccess = options.GetEditorConfigOption(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInMemberAccess, fallbackOptions.PreferPredefinedTypeKeywordInMemberAccess), - PreferPredefinedTypeKeywordInDeclaration = options.GetEditorConfigOption(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration, fallbackOptions.PreferPredefinedTypeKeywordInDeclaration), + QualifyFieldAccess = options.GetOption(CodeStyleOptions2.QualifyFieldAccess, language, fallbackOptions.QualifyFieldAccess), + QualifyPropertyAccess = options.GetOption(CodeStyleOptions2.QualifyPropertyAccess, language, fallbackOptions.QualifyPropertyAccess), + QualifyMethodAccess = options.GetOption(CodeStyleOptions2.QualifyMethodAccess, language, fallbackOptions.QualifyMethodAccess), + QualifyEventAccess = options.GetOption(CodeStyleOptions2.QualifyEventAccess, language, fallbackOptions.QualifyEventAccess), + PreferPredefinedTypeKeywordInMemberAccess = options.GetOption(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInMemberAccess, language, fallbackOptions.PreferPredefinedTypeKeywordInMemberAccess), + PreferPredefinedTypeKeywordInDeclaration = options.GetOption(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration, language, fallbackOptions.PreferPredefinedTypeKeywordInDeclaration), }; } #if !CODE_STYLE - public static SimplifierOptions GetSimplifierOptions(this AnalyzerConfigOptions options, SimplifierOptions? fallbackOptions, LanguageServices languageServices) + public static SimplifierOptions GetSimplifierOptions(this IOptionsReader options, SimplifierOptions? fallbackOptions, LanguageServices languageServices) => languageServices.GetRequiredService().GetSimplifierOptions(options, fallbackOptions); public static async ValueTask GetSimplifierOptionsAsync(this Document document, SimplifierOptions? fallbackOptions, CancellationToken cancellationToken) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/TestHooks/TaskExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/TestHooks/TaskExtensions.cs new file mode 100644 index 0000000000000..275a60df30a34 --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/TestHooks/TaskExtensions.cs @@ -0,0 +1,133 @@ +// 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.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Shared.TestHooks +{ + internal static partial class TaskExtensions + { + // Following code is copied from Microsoft.VisualStudio.Threading.TplExtensions (renamed to avoid ambiguity) + // https://github.com/microsoft/vs-threading/blob/main/src/Microsoft.VisualStudio.Threading/TplExtensions.cs + + /// + /// Returns an awaitable for the specified task that will never throw, even if the source task + /// faults or is canceled. + /// + /// The task whose completion should signal the completion of the returned awaitable. + /// if set to true the continuation will be scheduled on the caller's context; false to always execute the continuation on the threadpool. + /// An awaitable. + public static NoThrowTaskAwaitable NoThrowAwaitableInternal(this Task task, bool captureContext = true) + { + return new NoThrowTaskAwaitable(task, captureContext); + } + + /// + /// An awaitable that wraps a task and never throws an exception when waited on. + /// + public readonly struct NoThrowTaskAwaitable + { + /// + /// The task. + /// + private readonly Task _task; + + /// + /// A value indicating whether the continuation should be scheduled on the current sync context. + /// + private readonly bool _captureContext; + + /// + /// Initializes a new instance of the struct. + /// + /// The task. + /// Whether the continuation should be scheduled on the current sync context. + public NoThrowTaskAwaitable(Task task, bool captureContext) + { + Contract.ThrowIfNull(task, nameof(task)); + _task = task; + _captureContext = captureContext; + } + + /// + /// Gets the awaiter. + /// + /// The awaiter. + public NoThrowTaskAwaiter GetAwaiter() + { + return new NoThrowTaskAwaiter(_task, _captureContext); + } + } + + /// + /// An awaiter that wraps a task and never throws an exception when waited on. + /// + public readonly struct NoThrowTaskAwaiter : ICriticalNotifyCompletion + { + /// + /// The task. + /// + private readonly Task _task; + + /// + /// A value indicating whether the continuation should be scheduled on the current sync context. + /// + private readonly bool _captureContext; + + /// + /// Initializes a new instance of the struct. + /// + /// The task. + /// if set to true [capture context]. + public NoThrowTaskAwaiter(Task task, bool captureContext) + { + Contract.ThrowIfNull(task, nameof(task)); + _task = task; + _captureContext = captureContext; + } + + /// + /// Gets a value indicating whether the task has completed. + /// + public bool IsCompleted + { + get { return _task.IsCompleted; } + } + + /// + /// Schedules a delegate for execution at the conclusion of a task's execution. + /// + /// The action. + public void OnCompleted(Action continuation) + { + _task.ConfigureAwait(_captureContext).GetAwaiter().OnCompleted(continuation); + } + + /// + /// Schedules a delegate for execution at the conclusion of a task's execution + /// without capturing the ExecutionContext. + /// + /// The action. + public void UnsafeOnCompleted(Action continuation) + { + _task.ConfigureAwait(_captureContext).GetAwaiter().UnsafeOnCompleted(continuation); + } + + /// + /// Does nothing. + /// +#pragma warning disable CA1822 // Mark members as static + public void GetResult() +#pragma warning restore CA1822 // Mark members as static + { + // Never throw here. + } + } + } +} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/ValuesSources/WeaklyCachedRecoverableValueSource.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/ValuesSources/WeaklyCachedRecoverableValueSource.cs deleted file mode 100644 index 9076b37a371ed..0000000000000 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/ValuesSources/WeaklyCachedRecoverableValueSource.cs +++ /dev/null @@ -1,162 +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 Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.Host -{ - /// - /// This class is a that holds onto a value weakly, - /// but can save its value and recover it on demand if needed. - /// - /// The initial value comes from the specified in the constructor. - /// Derived types implement SaveAsync and RecoverAsync. - /// - internal abstract class WeaklyCachedRecoverableValueSource : ValueSource where T : class - { - private SemaphoreSlim? _lazyGate; // Lazily created. Access via the Gate property - private bool _saved; - private WeakReference? _weakReference; - private ValueSource _recoverySource; - - public WeaklyCachedRecoverableValueSource(ValueSource initialValue) - => _recoverySource = initialValue; - - /// - /// Override this to save the state of the instance so it can be recovered. - /// This method will only ever be called once. - /// - protected abstract Task SaveAsync(T instance, CancellationToken cancellationToken); - - /// - /// Override this method to implement asynchronous recovery semantics. - /// This method may be called multiple times. - /// - protected abstract Task RecoverAsync(CancellationToken cancellationToken); - - /// - /// Override this method to implement synchronous recovery semantics. - /// This method may be called multiple times. - /// - protected abstract T Recover(CancellationToken cancellationToken); - - // enforce saving in a queue so save's don't overload the thread pool. - private static Task s_latestTask = Task.CompletedTask; - private static readonly NonReentrantLock s_taskGuard = new(); - - private SemaphoreSlim Gate => LazyInitialization.EnsureInitialized(ref _lazyGate, SemaphoreSlimFactory.Instance); - -#pragma warning disable CS8610 // Nullability of reference types in type of parameter doesn't match overridden member. (The compiler incorrectly identifies this as a change.) - public override bool TryGetValue([NotNullWhen(true)] out T? value) -#pragma warning restore CS8610 // Nullability of reference types in type of parameter doesn't match overridden member. - { - // It has 2 fields that can hold onto the value. if we only check weakInstance, we will - // return false for the initial case where weakInstance is set to s_noReference even if - // value can be retrieved from _recoverySource. so we check both here. - var weakReference = _weakReference; - return weakReference != null && weakReference.TryGetTarget(out value) || - _recoverySource.TryGetValue(out value); - } - - public override T GetValue(CancellationToken cancellationToken) - { - cancellationToken.ThrowIfCancellationRequested(); - - var weakReference = _weakReference; - if (weakReference == null || !weakReference.TryGetTarget(out var instance)) - { - Task? saveTask = null; - using (Gate.DisposableWait(cancellationToken)) - { - if (_weakReference == null || !_weakReference.TryGetTarget(out instance)) - { - instance = _recoverySource.GetValue(cancellationToken); - saveTask = EnsureInstanceIsSavedAsync(instance); - } - } - - if (saveTask != null) - { - ResetRecoverySource(saveTask, instance); - } - } - - return instance; - } - - public override async Task GetValueAsync(CancellationToken cancellationToken) - { - var weakReference = _weakReference; - if (weakReference == null || !weakReference.TryGetTarget(out var instance)) - { - Task? saveTask = null; - using (await Gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false)) - { - if (_weakReference == null || !_weakReference.TryGetTarget(out instance)) - { - instance = await _recoverySource.GetValueAsync(cancellationToken).ConfigureAwait(false); - saveTask = EnsureInstanceIsSavedAsync(instance); - } - } - - if (saveTask != null) - { - ResetRecoverySource(saveTask, instance); - } - } - - return instance; - } - - private void ResetRecoverySource(Task saveTask, T instance) - { - saveTask.SafeContinueWith(t => - { - using (Gate.DisposableWait(CancellationToken.None)) - { - // Only assume the instance is saved if the saveTask completed successfully. If the save did not - // complete, we can still rely on a constant value source to provide the instance. - _recoverySource = saveTask.Status == TaskStatus.RanToCompletion - ? new AsyncLazy(RecoverAsync, Recover, cacheResult: false) - : new AsyncLazy(instance); - - // Need to keep instance alive until recovery source is updated. - GC.KeepAlive(instance); - } - }, TaskScheduler.Default); - } - - private Task? EnsureInstanceIsSavedAsync(T instance) - { - if (_weakReference == null) - { - _weakReference = new WeakReference(instance); - } - else - { - _weakReference.SetTarget(instance); - } - - if (!_saved) - { - _saved = true; - using (s_taskGuard.DisposableWait()) - { - // force all save tasks to be in sequence so we don't hog all the threads - s_latestTask = s_latestTask.SafeContinueWithFromAsync(t => - SaveAsync(instance, CancellationToken.None), CancellationToken.None, TaskScheduler.Default); - return s_latestTask; - } - } - -#pragma warning disable VSTHRD114 // Avoid returning a null Task (False positive: https://github.com/microsoft/vs-threading/issues/637) - return null; -#pragma warning restore VSTHRD114 // Avoid returning a null Task - } - } -} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/CodeGeneration/VisualBasicCodeGenerationOptions.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/CodeGeneration/VisualBasicCodeGenerationOptions.vb index 97259147945ae..820214c39ef35 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/CodeGeneration/VisualBasicCodeGenerationOptions.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/CodeGeneration/VisualBasicCodeGenerationOptions.vb @@ -42,10 +42,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Friend Module VisualBasicCodeGenerationOptionsProviders - Public Function GetVisualBasicCodeGenerationOptions(options As AnalyzerConfigOptions, fallbackOptions As VisualBasicCodeGenerationOptions) As VisualBasicCodeGenerationOptions + Public Function GetVisualBasicCodeGenerationOptions(options As IOptionsReader, fallbackOptions As VisualBasicCodeGenerationOptions) As VisualBasicCodeGenerationOptions + If fallbackOptions Is Nothing Then + fallbackOptions = VisualBasicCodeGenerationOptions.Default + End If + Return New VisualBasicCodeGenerationOptions() With { - .Common = options.GetCommonCodeGenerationOptions(fallbackOptions.Common) + .Common = options.GetCommonCodeGenerationOptions(LanguageNames.VisualBasic, fallbackOptions.Common) } End Function End Module diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/CodeStyle/VisualBasicCodeStyleOptions.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/CodeStyle/VisualBasicCodeStyleOptions.vb index d25820c268b41..f5190639c6de6 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/CodeStyle/VisualBasicCodeStyleOptions.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/CodeStyle/VisualBasicCodeStyleOptions.vb @@ -10,72 +10,46 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeStyle Friend NotInheritable Class VisualBasicCodeStyleOptions Private Shared ReadOnly s_allOptionsBuilder As ImmutableArray(Of IOption2).Builder = ImmutableArray.CreateBuilder(Of IOption2) - Shared Sub New() - AllOptions = s_allOptionsBuilder.ToImmutable() - End Sub - - Private Shared Function CreateOption(Of T)(group As OptionGroup, name As String, defaultValue As T, storageLocation As OptionStorageLocation2) As Option2(Of T) - Return CodeStyleHelpers.CreateOption(group, NameOf(VisualBasicCodeStyleOptions), name, defaultValue, s_allOptionsBuilder, storageLocation, LanguageNames.VisualBasic) - End Function - - Private Shared Function CreateOption(Of T)(group As OptionGroup, name As String, defaultValue As T, storageLocation1 As OptionStorageLocation2, storageLocation2 As OptionStorageLocation2) As Option2(Of T) - Return CodeStyleHelpers.CreateOption(group, NameOf(VisualBasicCodeStyleOptions), name, defaultValue, s_allOptionsBuilder, storageLocation1, storageLocation2, LanguageNames.VisualBasic) - End Function - - Private Shared Function CreateOption(group As OptionGroup, name As String, defaultValue As CodeStyleOption2(Of Boolean), editorconfigKeyName As String, roamingProfileStorageKeyName As String) As Option2(Of CodeStyleOption2(Of Boolean)) - Return CreateOption(group, name, defaultValue, EditorConfigStorageLocation.ForBoolCodeStyleOption(editorconfigKeyName, defaultValue), New RoamingProfileStorageLocation(roamingProfileStorageKeyName)) + Private Shared Function CreateOption(Of T)( + group As OptionGroup, + name As String, + defaultValue As CodeStyleOption2(Of T), + Optional serializerFactory As Func(Of CodeStyleOption2(Of T), EditorConfigValueSerializer(Of CodeStyleOption2(Of T))) = Nothing) As Option2(Of CodeStyleOption2(Of T)) + Return s_allOptionsBuilder.CreateEditorConfigOption(name, defaultValue, group, LanguageNames.VisualBasic, serializerFactory) End Function - Private Shared Function CreateOption(group As OptionGroup, name As String, defaultValue As CodeStyleOption2(Of String), editorconfigKeyName As String, roamingProfileStorageKeyName As String) As Option2(Of CodeStyleOption2(Of String)) - Return CreateOption( - group, name, defaultValue, - EditorConfigStorageLocation.ForStringCodeStyleOption(editorconfigKeyName, defaultValue), - New RoamingProfileStorageLocation(roamingProfileStorageKeyName)) - End Function - - Public Shared ReadOnly Property AllOptions As ImmutableArray(Of IOption2) - Public Shared ReadOnly PreferredModifierOrder As Option2(Of CodeStyleOption2(Of String)) = CreateOption( - VisualBasicCodeStyleOptionGroups.Modifier, NameOf(PreferredModifierOrder), - VisualBasicIdeCodeStyleOptions.Default.PreferredModifierOrder, + VisualBasicCodeStyleOptionGroups.Modifier, "visual_basic_preferred_modifier_order", - $"TextEditor.%LANGUAGE%.Specific.{NameOf(PreferredModifierOrder)}") + VisualBasicIdeCodeStyleOptions.Default.PreferredModifierOrder) Public Shared ReadOnly PreferIsNotExpression As Option2(Of CodeStyleOption2(Of Boolean)) = CreateOption( - VisualBasicCodeStyleOptionGroups.ExpressionLevelPreferences, NameOf(PreferIsNotExpression), - VisualBasicIdeCodeStyleOptions.Default.PreferIsNotExpression, + VisualBasicCodeStyleOptionGroups.ExpressionLevelPreferences, "visual_basic_style_prefer_isnot_expression", - $"TextEditor.%LANGUAGE%.Specific.{NameOf(PreferIsNotExpression)}") + VisualBasicIdeCodeStyleOptions.Default.PreferIsNotExpression) Public Shared ReadOnly PreferSimplifiedObjectCreation As Option2(Of CodeStyleOption2(Of Boolean)) = CreateOption( - VisualBasicCodeStyleOptionGroups.ExpressionLevelPreferences, NameOf(PreferSimplifiedObjectCreation), - VisualBasicIdeCodeStyleOptions.Default.PreferSimplifiedObjectCreation, + VisualBasicCodeStyleOptionGroups.ExpressionLevelPreferences, "visual_basic_style_prefer_simplified_object_creation", - $"TextEditor.%LANGUAGE%.Specific.{NameOf(PreferSimplifiedObjectCreation)}") + VisualBasicIdeCodeStyleOptions.Default.PreferSimplifiedObjectCreation) + + Public Shared ReadOnly UnusedValueExpressionStatement As Option2(Of CodeStyleOption2(Of UnusedValuePreference)) = CreateOption( + VisualBasicCodeStyleOptionGroups.ExpressionLevelPreferences, + "visual_basic_style_unused_value_expression_statement_preference", + VisualBasicIdeCodeStyleOptions.Default.UnusedValueExpressionStatement, + AddressOf CodeStyleHelpers.GetUnusedValuePreferenceSerializer) - Public Shared ReadOnly UnusedValueExpressionStatement As Option2(Of CodeStyleOption2(Of UnusedValuePreference)) = - CodeStyleHelpers.CreateUnusedExpressionAssignmentOption( - group:=VisualBasicCodeStyleOptionGroups.ExpressionLevelPreferences, - feature:=NameOf(VisualBasicCodeStyleOptions), - name:=NameOf(UnusedValueExpressionStatement), - editorConfigName:="visual_basic_style_unused_value_expression_statement_preference", - defaultValue:=VisualBasicIdeCodeStyleOptions.Default.UnusedValueExpressionStatement, - optionsBuilder:=s_allOptionsBuilder, - languageName:=LanguageNames.VisualBasic) + Public Shared ReadOnly UnusedValueAssignment As Option2(Of CodeStyleOption2(Of UnusedValuePreference)) = CreateOption( + VisualBasicCodeStyleOptionGroups.ExpressionLevelPreferences, + "visual_basic_style_unused_value_assignment_preference", + VisualBasicIdeCodeStyleOptions.Default.UnusedValueAssignment, + AddressOf CodeStyleHelpers.GetUnusedValuePreferenceSerializer) - Public Shared ReadOnly UnusedValueAssignment As Option2(Of CodeStyleOption2(Of UnusedValuePreference)) = - CodeStyleHelpers.CreateUnusedExpressionAssignmentOption( - group:=VisualBasicCodeStyleOptionGroups.ExpressionLevelPreferences, - feature:=NameOf(VisualBasicCodeStyleOptions), - name:=NameOf(UnusedValueAssignment), - editorConfigName:="visual_basic_style_unused_value_assignment_preference", - defaultValue:=VisualBasicIdeCodeStyleOptions.Default.UnusedValueAssignment, - optionsBuilder:=s_allOptionsBuilder, - languageName:=LanguageNames.VisualBasic) + Public Shared ReadOnly Property AllOptions As ImmutableArray(Of IOption2) = s_allOptionsBuilder.ToImmutable() End Class Friend NotInheritable Class VisualBasicCodeStyleOptionGroups - Public Shared ReadOnly Modifier As New OptionGroup(CompilerExtensionsResources.Modifier_preferences, priority:=1) - Public Shared ReadOnly ExpressionLevelPreferences As New OptionGroup(CompilerExtensionsResources.Expression_level_preferences, priority:=2) + Public Shared ReadOnly Modifier As New OptionGroup(CompilerExtensionsResources.Modifier_preferences, priority:=1, parent:=CodeStyleOptionGroups.CodeStyle) + Public Shared ReadOnly ExpressionLevelPreferences As New OptionGroup(CompilerExtensionsResources.Expression_level_preferences, priority:=2, parent:=CodeStyleOptionGroups.CodeStyle) End Class End Namespace diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Indentation/VisualBasicSmartTokenFormatter.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Indentation/VisualBasicSmartTokenFormatter.vb index 07d4675771c7f..bb1204a4fb833 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Indentation/VisualBasicSmartTokenFormatter.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Indentation/VisualBasicSmartTokenFormatter.vb @@ -6,8 +6,6 @@ Imports System.Threading Imports Microsoft.CodeAnalysis.Formatting Imports Microsoft.CodeAnalysis.Formatting.Rules Imports Microsoft.CodeAnalysis.Indentation -Imports Microsoft.CodeAnalysis.Options -Imports Microsoft.CodeAnalysis.Host Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.CodeAnalysis.VisualBasic.Formatting diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Simplification/VisualBasicSimplification.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Simplification/VisualBasicSimplification.vb index a315f6336624f..68614df45033f 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Simplification/VisualBasicSimplification.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Simplification/VisualBasicSimplification.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports Microsoft.CodeAnalysis.Diagnostics +Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Simplification Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification @@ -17,7 +18,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification End Get End Property - Public Overrides Function GetSimplifierOptions(options As AnalyzerConfigOptions, fallbackOptions As SimplifierOptions) As SimplifierOptions + Public Overrides Function GetSimplifierOptions(options As IOptionsReader, fallbackOptions As SimplifierOptions) As SimplifierOptions Return options.GetVisualBasicSimplifierOptions(DirectCast(fallbackOptions, VisualBasicSimplifierOptions)) End Function End Class diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Simplification/VisualBasicSimplifierOptions.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Simplification/VisualBasicSimplifierOptions.vb index 8eca73f4b86c5..8f29a81d6f997 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Simplification/VisualBasicSimplifierOptions.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Simplification/VisualBasicSimplifierOptions.vb @@ -7,6 +7,7 @@ Imports Microsoft.CodeAnalysis.Simplification Imports Microsoft.CodeAnalysis.CodeStyle Imports System.Runtime.Serialization Imports System.Runtime.CompilerServices +Imports Microsoft.CodeAnalysis.Options Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification @@ -32,11 +33,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification Friend Module VisualBasicSimplifierOptionsProviders - Friend Function GetVisualBasicSimplifierOptions(options As AnalyzerConfigOptions, fallbackOptions As VisualBasicSimplifierOptions) As VisualBasicSimplifierOptions + Friend Function GetVisualBasicSimplifierOptions(options As IOptionsReader, fallbackOptions As VisualBasicSimplifierOptions) As VisualBasicSimplifierOptions fallbackOptions = If(fallbackOptions, VisualBasicSimplifierOptions.Default) Return New VisualBasicSimplifierOptions() With { - .Common = options.GetCommonSimplifierOptions(fallbackOptions.Common) + .Common = options.GetCommonSimplifierOptions(LanguageNames.VisualBasic, fallbackOptions.Common) } End Function End Module diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeActions/CSharpCodeFixOptionsProvider.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeActions/CSharpCodeFixOptionsProvider.cs index 3b0c013eb19a3..a5fbedfe907d6 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeActions/CSharpCodeFixOptionsProvider.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeActions/CSharpCodeFixOptionsProvider.cs @@ -29,7 +29,7 @@ internal readonly struct CSharpCodeFixOptionsProvider /// /// Document editorconfig options. /// - private readonly AnalyzerConfigOptions _options; + private readonly IOptionsReader _options; /// /// C# language services. @@ -41,7 +41,7 @@ internal readonly struct CSharpCodeFixOptionsProvider /// private readonly CodeActionOptionsProvider _fallbackOptions; - public CSharpCodeFixOptionsProvider(AnalyzerConfigOptions options, CodeActionOptionsProvider fallbackOptions, HostLanguageServices languageServices) + public CSharpCodeFixOptionsProvider(IOptionsReader options, CodeActionOptionsProvider fallbackOptions, HostLanguageServices languageServices) { _options = options; _fallbackOptions = fallbackOptions; @@ -78,10 +78,10 @@ internal SyntaxFormattingOptions GetFormattingOptions() public CodeStyleOption2 AccessibilityModifiersRequired => GetOption(CodeStyleOptions2.AccessibilityModifiersRequired, FallbackCodeStyleOptions.Common.AccessibilityModifiersRequired); private TValue GetOption(Option2 option, TValue defaultValue) - => _options.GetEditorConfigOption(option, defaultValue); + => _options.GetOption(option, defaultValue); private TValue GetOption(PerLanguageOption2 option, TValue defaultValue) - => _options.GetEditorConfigOption(option, defaultValue); + => _options.GetOption(option, _languageServices.Language, defaultValue); private CSharpIdeCodeStyleOptions FallbackCodeStyleOptions #if CODE_STYLE @@ -124,6 +124,6 @@ internal static class CSharpCodeFixOptionsProviders public static async ValueTask GetCSharpCodeFixOptionsProviderAsync(this Document document, CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) { var configOptions = await document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); - return new CSharpCodeFixOptionsProvider(configOptions, fallbackOptions, document.Project.GetExtendedLanguageServices()); + return new CSharpCodeFixOptionsProvider(configOptions.GetOptionsReader(), fallbackOptions, document.Project.GetExtendedLanguageServices()); } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/CSharpSyntaxContext.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/CSharpSyntaxContext.cs index 22890db620c2c..a4d750cd4dc39 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/CSharpSyntaxContext.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/CSharpSyntaxContext.cs @@ -281,7 +281,7 @@ private static CSharpSyntaxContext CreateContextWorker(Document document, Semant isLocalFunctionDeclarationContext: isLocalFunctionDeclarationContext, isLocalVariableDeclarationContext: syntaxTree.IsLocalVariableDeclarationContext(position, leftToken, cancellationToken), isNameOfContext: syntaxTree.IsNameOfContext(position, semanticModel, cancellationToken), - isNamespaceContext: syntaxTree.IsNamespaceContext(position, cancellationToken, semanticModelOpt: semanticModel), + isNamespaceContext: syntaxTree.IsNamespaceContext(position, cancellationToken, semanticModel), isNamespaceDeclarationNameContext: syntaxTree.IsNamespaceDeclarationNameContext(position, cancellationToken), isNonAttributeExpressionContext: isNonAttributeExpressionContext, isObjectCreationTypeContext: syntaxTree.IsObjectCreationTypeContext(position, leftToken, cancellationToken), @@ -296,7 +296,7 @@ private static CSharpSyntaxContext CreateContextWorker(Document document, Semant isRightSideOfNumericType: isRightSideOfNumericType, isStatementContext: isStatementContext, isTypeArgumentOfConstraintContext: syntaxTree.IsTypeArgumentOfConstraintClause(position, cancellationToken), - isTypeContext: syntaxTree.IsTypeContext(position, cancellationToken, semanticModelOpt: semanticModel), + isTypeContext: syntaxTree.IsTypeContext(position, cancellationToken, semanticModel), isTypeOfExpressionContext: syntaxTree.IsTypeOfExpressionContext(position, leftToken), isWithinAsyncMethod: ComputeIsWithinAsyncMethod(), precedingModifiers: precedingModifiers, diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/SyntaxTreeExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/SyntaxTreeExtensions.cs index 5ce100d79990e..5a45378e561fd 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/SyntaxTreeExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/SyntaxTreeExtensions.cs @@ -611,7 +611,7 @@ public static bool IsNamespaceContext( this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken, - SemanticModel? semanticModelOpt = null) + SemanticModel? semanticModel = null) { // first do quick exit check if (syntaxTree.IsInNonUserCode(position, cancellationToken) || @@ -658,7 +658,7 @@ public static bool IsNamespaceContext( // if it is not using directive location, most of places where // type can appear, namespace can appear as well - return syntaxTree.IsTypeContext(position, cancellationToken, semanticModelOpt); + return syntaxTree.IsTypeContext(position, cancellationToken, semanticModel); } public static bool IsNamespaceDeclarationNameContext(this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) @@ -710,7 +710,7 @@ public static bool IsDefinitelyNotTypeContext(this SyntaxTree syntaxTree, int po } public static bool IsTypeContext( - this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken, SemanticModel? semanticModelOpt = null) + this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken, SemanticModel? semanticModel = null) { // first do quick exit check if (syntaxTree.IsDefinitelyNotTypeContext(position, cancellationToken)) @@ -732,9 +732,9 @@ public static bool IsTypeContext( syntaxTree.IsCatchVariableDeclarationContext(position, cancellationToken) || syntaxTree.IsDefiniteCastTypeContext(position, tokenOnLeftOfPosition) || syntaxTree.IsDelegateReturnTypeContext(position, tokenOnLeftOfPosition) || - syntaxTree.IsExpressionContext(position, tokenOnLeftOfPosition, attributes: true, cancellationToken: cancellationToken, semanticModelOpt: semanticModelOpt) || + syntaxTree.IsExpressionContext(position, tokenOnLeftOfPosition, attributes: true, cancellationToken: cancellationToken, semanticModelOpt: semanticModel) || syntaxTree.IsPrimaryFunctionExpressionContext(position, tokenOnLeftOfPosition) || - syntaxTree.IsGenericTypeArgumentContext(position, tokenOnLeftOfPosition, cancellationToken, semanticModelOpt) || + syntaxTree.IsGenericTypeArgumentContext(position, tokenOnLeftOfPosition, cancellationToken, semanticModel) || syntaxTree.IsFunctionPointerTypeArgumentContext(position, tokenOnLeftOfPosition, cancellationToken) || syntaxTree.IsFixedVariableDeclarationContext(position, tokenOnLeftOfPosition) || syntaxTree.IsImplicitOrExplicitOperatorTypeContext(position, tokenOnLeftOfPosition) || @@ -764,6 +764,7 @@ public static bool IsBaseClassOrInterfaceContext(this SyntaxTree syntaxTree, int { // class C : | // class C : Bar, | + // NOT enum E : | var token = syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken); token = token.GetPreviousTokenIfTouchingWord(position); @@ -771,7 +772,7 @@ public static bool IsBaseClassOrInterfaceContext(this SyntaxTree syntaxTree, int if (token.IsKind(SyntaxKind.ColonToken) || token.IsKind(SyntaxKind.CommaToken)) { - if (token.Parent.IsKind(SyntaxKind.BaseList)) + if (token.Parent is BaseListSyntax { Parent: not EnumDeclarationSyntax }) { return true; } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpAddImportsService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpAddImportsService.cs index b43e9e596de03..e61a328de3c6d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpAddImportsService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpAddImportsService.cs @@ -15,6 +15,7 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.AddImport @@ -29,8 +30,11 @@ public CSharpAddImportsService() { } - public override CodeStyleOption2 GetUsingDirectivePlacementCodeStyleOption(AnalyzerConfigOptions configOptions, CodeStyleOption2 fallbackValue) - => configOptions.GetEditorConfigOption(CSharpCodeStyleOptions.PreferredUsingDirectivePlacement, fallbackValue); + protected override string Language + => LanguageNames.CSharp; + + public override CodeStyleOption2 GetUsingDirectivePlacementCodeStyleOption(IOptionsReader configOptions, CodeStyleOption2 fallbackValue) + => configOptions.GetOption(CSharpCodeStyleOptions.PreferredUsingDirectivePlacement, fallbackValue); // C# doesn't have global imports. protected override ImmutableArray GetGlobalImports(Compilation compilation, SyntaxGenerator generator) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpTypeInferenceService.TypeInferrer.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpTypeInferenceService.TypeInferrer.cs index e7c61aa7ee887..40b0cb5ba32d2 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpTypeInferenceService.TypeInferrer.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpTypeInferenceService.TypeInferrer.cs @@ -2026,13 +2026,13 @@ private ITypeSymbol UnwrapTaskLike(ITypeSymbol type, bool isAsync) { if (isAsync) { - if (type.OriginalDefinition.Equals(this.Compilation.TaskOfTType())) + if (type.OriginalDefinition.Equals(this.Compilation.TaskOfTType()) || type.OriginalDefinition.Equals(this.Compilation.ValueTaskOfTType())) { var namedTypeSymbol = (INamedTypeSymbol)type; return namedTypeSymbol.TypeArguments[0]; } - if (type.OriginalDefinition.Equals(this.Compilation.TaskType())) + if (type.OriginalDefinition.Equals(this.Compilation.TaskType()) || type.OriginalDefinition.Equals(this.Compilation.ValueTaskType())) { return this.Compilation.GetSpecialType(SpecialType.System_Void); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/AddImport/AddImportPlacementOptionsProviders.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/AddImport/AddImportPlacementOptionsProviders.cs index 5c34f9769790d..7cb64c67fb684 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/AddImport/AddImportPlacementOptionsProviders.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/AddImport/AddImportPlacementOptionsProviders.cs @@ -5,6 +5,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.AddImport; @@ -14,7 +15,8 @@ internal static async ValueTask GetAddImportPlacement { #if CODE_STYLE var syntaxTree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); - return addImportsService.GetAddImportOptions(document.Project.AnalyzerOptions.AnalyzerConfigOptionsProvider.GetOptions(syntaxTree), allowInHiddenRegions: false, fallbackOptions: null); + var configOptions = document.Project.AnalyzerOptions.AnalyzerConfigOptionsProvider.GetOptions(syntaxTree).GetOptionsReader(); + return addImportsService.GetAddImportOptions(configOptions, allowInHiddenRegions: false, fallbackOptions: null); #else return await document.GetAddImportPlacementOptionsAsync(fallbackOptionsProvider, cancellationToken).ConfigureAwait(false); #endif diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeActions/CodeFixOptionsProvider.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeActions/CodeFixOptionsProvider.cs index 0e9cbc0e98721..ab6d958d4b1d1 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeActions/CodeFixOptionsProvider.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeActions/CodeFixOptionsProvider.cs @@ -25,7 +25,7 @@ internal readonly struct CodeFixOptionsProvider /// /// Document editorconfig options. /// - private readonly AnalyzerConfigOptions _options; + private readonly IOptionsReader _options; /// /// C# language services. @@ -37,7 +37,7 @@ internal readonly struct CodeFixOptionsProvider /// private readonly CodeActionOptionsProvider _fallbackOptions; - public CodeFixOptionsProvider(AnalyzerConfigOptions options, CodeActionOptionsProvider fallbackOptions, HostLanguageServices languageServices) + public CodeFixOptionsProvider(IOptionsReader options, CodeActionOptionsProvider fallbackOptions, HostLanguageServices languageServices) { _options = options; _fallbackOptions = fallbackOptions; @@ -49,17 +49,17 @@ public CodeFixOptionsProvider(AnalyzerConfigOptions options, CodeActionOptionsPr public string NewLine => GetOption(FormattingOptions2.NewLine, FallbackLineFormattingOptions.NewLine); public LineFormattingOptions GetLineFormattingOptions() - => _options.GetLineFormattingOptions(FallbackLineFormattingOptions); + => _options.GetLineFormattingOptions(_languageServices.Language, FallbackLineFormattingOptions); // SyntaxFormattingOptions public SyntaxFormattingOptions GetFormattingOptions(ISyntaxFormatting formatting) => formatting.GetFormattingOptions(_options, FallbackSyntaxFormattingOptions); - public AccessibilityModifiersRequired AccessibilityModifiersRequired => _options.GetEditorConfigOptionValue(CodeStyleOptions2.AccessibilityModifiersRequired, FallbackCommonSyntaxFormattingOptions.AccessibilityModifiersRequired); + public AccessibilityModifiersRequired AccessibilityModifiersRequired => _options.GetOptionValue(CodeStyleOptions2.AccessibilityModifiersRequired, _languageServices.Language, FallbackCommonSyntaxFormattingOptions.AccessibilityModifiersRequired); private TValue GetOption(PerLanguageOption2 option, TValue defaultValue) - => _options.GetEditorConfigOption(option, defaultValue); + => _options.GetOption(option, _languageServices.Language, defaultValue); private LineFormattingOptions FallbackLineFormattingOptions #if CODE_STYLE @@ -88,6 +88,6 @@ internal static class CodeFixOptionsProviders public static async ValueTask GetCodeFixOptionsAsync(this Document document, CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) { var configOptions = await document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); - return new CodeFixOptionsProvider(configOptions, fallbackOptions, document.Project.GetExtendedLanguageServices()); + return new CodeFixOptionsProvider(configOptions.GetOptionsReader(), fallbackOptions, document.Project.GetExtendedLanguageServices()); } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/AddImports/AbstractAddImportsService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/AddImports/AbstractAddImportsService.cs index f0993d7523df3..36a4e889838c2 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/AddImports/AbstractAddImportsService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/AddImports/AbstractAddImportsService.cs @@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.AddImport @@ -25,25 +26,26 @@ protected AbstractAddImportsService() { } + protected abstract string Language { get; } protected abstract SyntaxNode? GetAlias(TUsingOrAliasSyntax usingOrAlias); protected abstract ImmutableArray GetGlobalImports(Compilation compilation, SyntaxGenerator generator); protected abstract SyntaxList GetUsingsAndAliases(SyntaxNode node); protected abstract SyntaxList GetExterns(SyntaxNode node); protected abstract bool IsStaticUsing(TUsingOrAliasSyntax usingOrAlias); - public AddImportPlacementOptions GetAddImportOptions(AnalyzerConfigOptions configOptions, bool allowInHiddenRegions, AddImportPlacementOptions? fallbackOptions) + public AddImportPlacementOptions GetAddImportOptions(IOptionsReader configOptions, bool allowInHiddenRegions, AddImportPlacementOptions? fallbackOptions) { fallbackOptions ??= AddImportPlacementOptions.Default; return new() { - PlaceSystemNamespaceFirst = configOptions.GetEditorConfigOption(GenerationOptions.PlaceSystemNamespaceFirst, fallbackOptions.PlaceSystemNamespaceFirst), + PlaceSystemNamespaceFirst = configOptions.GetOption(GenerationOptions.PlaceSystemNamespaceFirst, Language, fallbackOptions.PlaceSystemNamespaceFirst), UsingDirectivePlacement = GetUsingDirectivePlacementCodeStyleOption(configOptions, fallbackOptions.UsingDirectivePlacement), AllowInHiddenRegions = allowInHiddenRegions }; } - public abstract CodeStyleOption2 GetUsingDirectivePlacementCodeStyleOption(AnalyzerConfigOptions configOptions, CodeStyleOption2 fallbackValue); + public abstract CodeStyleOption2 GetUsingDirectivePlacementCodeStyleOption(IOptionsReader configOptions, CodeStyleOption2 fallbackValue); private bool IsSimpleUsing(TUsingOrAliasSyntax usingOrAlias) => !IsAlias(usingOrAlias) && !IsStaticUsing(usingOrAlias); private bool IsAlias(TUsingOrAliasSyntax usingOrAlias) => GetAlias(usingOrAlias) != null; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/AddImports/IAddImportsService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/AddImports/IAddImportsService.cs index 9b9acf9ca9edd..ca9a155b0e8e3 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/AddImports/IAddImportsService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/AddImports/IAddImportsService.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; @@ -18,7 +19,7 @@ namespace Microsoft.CodeAnalysis.AddImport { internal interface IAddImportsService : ILanguageService { - AddImportPlacementOptions GetAddImportOptions(AnalyzerConfigOptions configOptions, bool allowInHiddenRegions, AddImportPlacementOptions? fallbackOptions); + AddImportPlacementOptions GetAddImportOptions(IOptionsReader configOptions, bool allowInHiddenRegions, AddImportPlacementOptions? fallbackOptions); /// /// Returns true if the tree already has an existing import syntactically equivalent to diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/VisualBasicAddImportsService.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/VisualBasicAddImportsService.vb index 0a1abe6113fb5..112c815cf4bb5 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/VisualBasicAddImportsService.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/VisualBasicAddImportsService.vb @@ -10,6 +10,7 @@ Imports Microsoft.CodeAnalysis.CodeStyle Imports Microsoft.CodeAnalysis.Diagnostics Imports Microsoft.CodeAnalysis.Editing Imports Microsoft.CodeAnalysis.Host.Mef +Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.CodeAnalysis.VisualBasic.Utilities @@ -30,6 +31,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.AddImports Private Shared ReadOnly ImportsStatementComparer As ImportsStatementComparer = New ImportsStatementComparer(New CaseInsensitiveTokenComparer()) + Protected Overrides ReadOnly Property Language As String + Get + Return LanguageNames.VisualBasic + End Get + End Property + Protected Overrides Function IsEquivalentImport(a As SyntaxNode, b As SyntaxNode) As Boolean Dim importsA = TryCast(a, ImportsStatementSyntax) Dim importsB = TryCast(b, ImportsStatementSyntax) @@ -59,7 +66,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.AddImports FirstOrDefault()?.Alias End Function - Public Overrides Function GetUsingDirectivePlacementCodeStyleOption(configOptions As AnalyzerConfigOptions, fallbackValue As CodeStyleOption2(Of AddImportPlacement)) As CodeStyleOption2(Of AddImportPlacement) + Public Overrides Function GetUsingDirectivePlacementCodeStyleOption(configOptions As IOptionsReader, fallbackValue As CodeStyleOption2(Of AddImportPlacement)) As CodeStyleOption2(Of AddImportPlacement) ' Visual Basic doesn't support imports inside namespaces Return fallbackValue End Function diff --git a/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicCodeGenerationService.vb b/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicCodeGenerationService.vb index 0f91ee320806e..f6fe07c804060 100644 --- a/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicCodeGenerationService.vb +++ b/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicCodeGenerationService.vb @@ -11,6 +11,7 @@ Imports Microsoft.CodeAnalysis.Diagnostics Imports Microsoft.CodeAnalysis.Editing Imports Microsoft.CodeAnalysis.Host Imports Microsoft.CodeAnalysis.LanguageService +Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService @@ -31,8 +32,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration End Get End Property - Public Overrides Function GetCodeGenerationOptions(options As AnalyzerConfigOptions, fallbackOptions As CodeGenerationOptions) As CodeGenerationOptions - Return VisualBasicCodeGenerationOptions.Default + Public Overrides Function GetCodeGenerationOptions(options As IOptionsReader, fallbackOptions As CodeGenerationOptions) As CodeGenerationOptions + Return options.GetVisualBasicCodeGenerationOptions(DirectCast(fallbackOptions, VisualBasicCodeGenerationOptions)) End Function Public Overloads Overrides Function GetDestination(containerNode As SyntaxNode) As CodeGenerationDestination diff --git a/src/Workspaces/VisualBasic/Portable/CodeStyle/VisualBasicCodeStyleOptionsProvider.vb b/src/Workspaces/VisualBasic/Portable/CodeStyle/VisualBasicCodeStyleOptionsProvider.vb deleted file mode 100644 index a62b4cd1515cc..0000000000000 --- a/src/Workspaces/VisualBasic/Portable/CodeStyle/VisualBasicCodeStyleOptionsProvider.vb +++ /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. - -Imports System.Collections.Immutable -Imports System.Composition -Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.Options -Imports Microsoft.CodeAnalysis.Options.Providers - -Namespace Microsoft.CodeAnalysis.VisualBasic.CodeStyle - - Friend NotInheritable Class VisualBasicCodeStyleOptionsProvider - Implements IOptionProvider - - - - Public Sub New() - End Sub - - Public ReadOnly Property Options As ImmutableArray(Of IOption) Implements IOptionProvider.Options - Get - Return VisualBasicCodeStyleOptions.AllOptions.As(Of IOption) - End Get - End Property - End Class -End Namespace diff --git a/src/Workspaces/VisualBasic/Portable/CodeStyle/VisualBasicCodeStyleService.vb b/src/Workspaces/VisualBasic/Portable/CodeStyle/VisualBasicCodeStyleService.vb index 27edfd0bd80d3..5507e7f20f1d3 100644 --- a/src/Workspaces/VisualBasic/Portable/CodeStyle/VisualBasicCodeStyleService.vb +++ b/src/Workspaces/VisualBasic/Portable/CodeStyle/VisualBasicCodeStyleService.vb @@ -4,12 +4,14 @@ Imports System Imports System.Composition +Imports System.Runtime.CompilerServices Imports Microsoft.CodeAnalysis.CodeStyle Imports Microsoft.CodeAnalysis.Host.Mef +Imports Microsoft.CodeAnalysis.Options Namespace Microsoft.CodeAnalysis.VisualBasic.CodeStyle - Friend NotInheritable Class CSharpCodeStyleService + Friend NotInheritable Class VisualBasicCodeStyleService Implements ICodeStyleService @@ -22,5 +24,26 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeStyle Return VisualBasicIdeCodeStyleOptions.Default End Get End Property + + Public Function GetIdeCodeStyleOptions(options As IOptionsReader, fallbackOptions As IdeCodeStyleOptions) As IdeCodeStyleOptions Implements ICodeStyleService.GetIdeCodeStyleOptions + Return options.GetVisualBasicCodeStyleOptions(DirectCast(fallbackOptions, VisualBasicIdeCodeStyleOptions)) + End Function End Class + + Friend Module VisualBasicIdeCodeStyleOptionsProviders + + Public Function GetVisualBasicCodeStyleOptions(options As IOptionsReader, fallbackOptions As VisualBasicIdeCodeStyleOptions) As VisualBasicIdeCodeStyleOptions + If fallbackOptions Is Nothing Then + fallbackOptions = VisualBasicIdeCodeStyleOptions.Default + End If + + Return New VisualBasicIdeCodeStyleOptions( + Common:=options.GetCommonCodeStyleOptions(LanguageNames.VisualBasic, fallbackOptions.Common), + PreferredModifierOrder:=options.GetOption(VisualBasicCodeStyleOptions.PreferredModifierOrder, fallbackOptions.PreferredModifierOrder), + PreferIsNotExpression:=options.GetOption(VisualBasicCodeStyleOptions.PreferIsNotExpression, fallbackOptions.PreferIsNotExpression), + PreferSimplifiedObjectCreation:=options.GetOption(VisualBasicCodeStyleOptions.PreferSimplifiedObjectCreation, fallbackOptions.PreferSimplifiedObjectCreation), + UnusedValueExpressionStatement:=options.GetOption(VisualBasicCodeStyleOptions.UnusedValueExpressionStatement, fallbackOptions.UnusedValueExpressionStatement), + UnusedValueAssignment:=options.GetOption(VisualBasicCodeStyleOptions.UnusedValueAssignment, fallbackOptions.UnusedValueAssignment)) + End Function + End Module End Namespace diff --git a/src/Workspaces/VisualBasic/Portable/Formatting/VisualBasicSyntaxFormatting.vb b/src/Workspaces/VisualBasic/Portable/Formatting/VisualBasicSyntaxFormatting.vb index 1060cafe60786..0b2fadb155f7d 100644 --- a/src/Workspaces/VisualBasic/Portable/Formatting/VisualBasicSyntaxFormatting.vb +++ b/src/Workspaces/VisualBasic/Portable/Formatting/VisualBasicSyntaxFormatting.vb @@ -7,6 +7,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis.Diagnostics Imports Microsoft.CodeAnalysis.Formatting Imports Microsoft.CodeAnalysis.Formatting.Rules +Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Shared.Collections Imports Microsoft.CodeAnalysis.Text @@ -34,7 +35,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Formatting End Get End Property - Public Overrides Function GetFormattingOptions(options As AnalyzerConfigOptions, fallbackOptions As SyntaxFormattingOptions) As SyntaxFormattingOptions + Public Overrides Function GetFormattingOptions(options As IOptionsReader, fallbackOptions As SyntaxFormattingOptions) As SyntaxFormattingOptions Return VisualBasicSyntaxFormattingOptions.Create(options, DirectCast(fallbackOptions, VisualBasicSyntaxFormattingOptions)) End Function diff --git a/src/Workspaces/VisualBasic/Portable/Formatting/VisualBasicSyntaxFormattingOptions.vb b/src/Workspaces/VisualBasic/Portable/Formatting/VisualBasicSyntaxFormattingOptions.vb index 4d02c0881513c..cc8e9beb6a39e 100644 --- a/src/Workspaces/VisualBasic/Portable/Formatting/VisualBasicSyntaxFormattingOptions.vb +++ b/src/Workspaces/VisualBasic/Portable/Formatting/VisualBasicSyntaxFormattingOptions.vb @@ -7,6 +7,7 @@ Imports Microsoft.CodeAnalysis.CodeStyle Imports Microsoft.CodeAnalysis.Diagnostics Imports Microsoft.CodeAnalysis.Editing Imports Microsoft.CodeAnalysis.Formatting +Imports Microsoft.CodeAnalysis.Options Namespace Microsoft.CodeAnalysis.VisualBasic.Formatting @@ -16,12 +17,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Formatting Public Shared ReadOnly [Default] As New VisualBasicSyntaxFormattingOptions() - Public Shared Shadows Function Create(options As AnalyzerConfigOptions, fallbackOptions As VisualBasicSyntaxFormattingOptions) As VisualBasicSyntaxFormattingOptions + Public Shared Shadows Function Create(options As IOptionsReader, fallbackOptions As VisualBasicSyntaxFormattingOptions) As VisualBasicSyntaxFormattingOptions fallbackOptions = If(fallbackOptions, [Default]) Return New VisualBasicSyntaxFormattingOptions() With { - .Common = options.GetCommonSyntaxFormattingOptions(fallbackOptions.Common) + .Common = options.GetCommonSyntaxFormattingOptions(LanguageNames.VisualBasic, fallbackOptions.Common) } End Function diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicSimplificationService.vb b/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicSimplificationService.vb index 3d380875d19ef..d7f51099454fc 100644 --- a/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicSimplificationService.vb +++ b/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicSimplificationService.vb @@ -9,6 +9,7 @@ Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.Diagnostics Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Internal.Log +Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Simplification Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.CodeAnalysis.VisualBasic.Utilities @@ -43,7 +44,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification End Get End Property - Public Overrides Function GetSimplifierOptions(options As AnalyzerConfigOptions, fallbackOptions As SimplifierOptions) As SimplifierOptions + Public Overrides Function GetSimplifierOptions(options As IOptionsReader, fallbackOptions As SimplifierOptions) As SimplifierOptions Return options.GetVisualBasicSimplifierOptions(DirectCast(fallbackOptions, VisualBasicSimplifierOptions)) End Function